qserver/qserver.c

710 lines
12 KiB
C

#pragma nda NDAOpen NDAClose NDAAction NDAInit 30 0xffff "--Quote Server\\H**"
#pragma lint -1
#pragma optimize -1
#include <Types.h>
#include <GSOS.h>
#include <Memory.h>
#include <Locator.h>
#include <Loader.h>
#include <Desk.h>
#include <Event.h>
#include <Window.h>
#include <Control.h>
#include <Resources.h>
#include <Quickdraw.h>
#include <QDAux.h>
#include <Font.h>
#include <stdfile.h>
#include <TextEdit.h>
#include <intmath.h>
#include <TCPIP.h>
#include <misctool.h>
#include <kstring.h>
#include "qserver.h"
Handle LoadQuote(word mID, Word rfile);
Word LoadConfig(Word MemID);
void UnloadConfig(void);
void DoConfig(Word MemID);
const char *ReqName = "\pTCP/IP~kelvin~qserver~";
/*
variables
*/
WindowPtr MyWindow;
Boolean FlagTCP;
Boolean FlagQS;
Boolean FlagQDAux;
Boolean FlagFM;
Boolean FlagTE;
Boolean FlagSF;
Boolean FlagLoadTCP;
Handle HandleFM;
Handle HandleTE;
Handle HandleSF;
Word MyID;
Word MyRID;
Word Ipid;
word rFile;
Handle rPath;
word rCount;
struct qentry
{
Word ipid;
Word state;
Longword tick;
};
#define QSIZE 16
struct qentry queue[QSIZE];
word total;
word current;
void fixstats(void)
{
static char stats[16];
Word i;
i = ksprintf(stats + 1, "%d : %d", current, total);
stats[0] = i; // pascal string
SetInfoRefCon((LongWord)stats, MyWindow);
DrawInfoBar(MyWindow);
}
void InsertString(word length, char *cp)
{
Handle handle;
TERecord **temp;
longword oldStart, oldEnd;
handle = (Handle)GetCtlHandleFromID(MyWindow, CtrlTE);
temp = (TERecord **)handle;
(**temp).textFlags &= (~fReadOnly);
TEGetSelection((pointer)&oldStart, (pointer)&oldEnd, handle);
TESetSelection((Pointer)-1, (Pointer)-1, handle);
TEInsert(teDataIsTextBlock, (Ref)cp, length,
NULL, NULL, /* no style info */
handle);
(**temp).textFlags |= fReadOnly;
TESetSelection((Pointer)oldStart, (Pointer)oldEnd, handle);
}
enum
{
STATE_NULL = 0,
STATE_ESTABLISH, // waiting to establish
STATE_QUOTE, // send the quote...
STATE_SEND // waiting for data to send
};
void QServer(void)
{
static srBuff srBuffer;
word delta;
int i;
delta = false;
TCPIPPoll();
for (i = 0; i < QSIZE; i++)
{
word ipid;
ipid = queue[i].ipid;
if (!ipid) continue;
TCPIPStatusTCP(ipid, &srBuffer);
switch (queue[i].state)
{
case STATE_ESTABLISH:
if (srBuffer.srState != TCPSESTABLISHED)
break;
queue[i].state = STATE_QUOTE;
// drop through and send the quote.
case STATE_QUOTE:
{
Handle h;
h = LoadQuote(MyID, rFile);
if (h)
{
HLock(h);
TCPIPWriteTCP(ipid, *h,
GetHandleSize(h), false, false);
DisposeHandle(h);
}
else
{
TCPIPWriteTCP(ipid, "Your quote here!\r\n",
18, false, false);
}
}
queue[i].state = STATE_SEND;
break;
case STATE_SEND:
if (srBuffer.srSndQueued == 0)
{
queue[i].ipid = 0;
queue[i].state = 0;
TCPIPCloseTCP(ipid);
current--;
delta = true;
}
break;
}
}
// check for a new connection.
if (current < QSIZE)
{
word child;
int i;
child = TCPIPAcceptTCP(Ipid, 0);
if (!_toolErr) for (i = 0; i < QSIZE; i++)
{
if (!queue[i].ipid)
{
static char buffer[16];
static char line[32];
int j;
TCPIPStatusTCP(child, &srBuffer);
queue[i].ipid = child;
if (srBuffer.srState == TCPSESTABLISHED)
queue[i].state = STATE_SEND;
else
queue[i].state = STATE_ESTABLISH;
queue[i].tick = GetTick();
current++;
total++;
delta = true;
TCPIPConvertIPToASCII(srBuffer.srDestIP,
buffer, 0);
j = ksprintf(line, "%p:%d\r",
buffer, srBuffer.srDestPort);
InsertString(j, line);
break;
}
}
}
if (delta) fixstats(); // statistics changed.
}
int StartServer(void)
{
int i;
word oFile;
word oDepth;
static char err[256];
total = current = 0;
if (!rPath)
{
InsertString(32, "Fatal: No quote file specified.\r");
return false;
}
HLock(rPath);
rFile = OpenResourceFile(readEnable, NULL, (pointer)*rPath);
if (_toolErr)
{
InsertString(ksprintf(err, "Fatal: Unable to open %g\r", *rPath),
err);
return false;
}
oFile = GetCurResourceFile();
SetCurResourceFile(rFile);
oDepth = SetResourceFileDepth(1);
rCount = CountResources(rTextForLETextBox2);
SetCurResourceFile(oFile);
SetResourceFileDepth(oDepth);
if (!rCount)
{
InsertString(ksprintf(err, "Fatal: Invalid quote file %g\r", *rPath),
err);
CloseResourceFile(rFile);
return false;
}
SetRandSeed(GetTick());
for (i = 0; i < QSIZE; i++)
{
queue[i].ipid = 0;
queue[i].state = 0;
}
Ipid = TCPIPLogin(MyID, 0, 0, 0, 64);
TCPIPSetSourcePort(Ipid, PORT_QOTD);
TCPIPListenTCP(Ipid);
FlagQS = true;
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStartQS);
HiliteCtlByID(noHilite, MyWindow, CtrlStopQS);
fixstats();
HUnlock(rPath);
return true;
}
int StopServer(void)
{
int i;
// close any q entries
for (i = 0; i < QSIZE; i++)
{
int ipid;
ipid = queue[i].ipid;
if (ipid)
{
TCPIPCloseTCP(ipid);
queue[i].ipid = 0;
}
}
TCPIPCloseTCP(Ipid);
TCPIPLogout(Ipid);
FlagQS = false;
Ipid = 0;
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStopQS);
HiliteCtlByID(noHilite, MyWindow, CtrlStartQS);
CloseResourceFile(rFile);
SetInfoRefCon((LongWord)"\pQuote Server stopped", MyWindow);
DrawInfoBar(MyWindow);
return true;
}
// activate/inactivate controls based on Marinetti status
void UpdateStatus(Boolean redraw)
{
if (FlagTCP) // TCP started
{
// deactivate
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStartM);
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStopQS);
// activate
HiliteCtlByID(noHilite, MyWindow, CtrlStopM);
HiliteCtlByID(noHilite, MyWindow, CtrlStartQS);
SetInfoRefCon((LongWord)"\pNetwork Connected", MyWindow);
}
else
{
// activate
HiliteCtlByID(noHilite, MyWindow, CtrlStartM);
// deactivate
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStopM);
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStartQS);
HiliteCtlByID(inactiveHilite, MyWindow, CtrlStopQS);
SetInfoRefCon((LongWord)"\pNetwork Disconnected", MyWindow);
}
if (redraw)
DrawInfoBar(MyWindow);
}
#pragma databank 1
/*
* watch for
*/
pascal word HandleRequest(word request, longword dataIn, longword dataOut)
{
Word oldRApp;
oldRApp = GetCurResourceApp();
SetCurResourceApp(MyID);
if (request == TCPIPSaysNetworkUp)
{
FlagTCP = true;
UpdateStatus(true);
}
if (request == TCPIPSaysNetworkDown)
{
if (FlagQS) StopServer();
FlagTCP = false;
Ipid = 0;
UpdateStatus(true);
}
SetCurResourceApp(oldRApp);
}
pascal void MarinettiCallback(char *str)
{
if (MyWindow)
{
SetInfoRefCon((LongWord)str, MyWindow);
DrawInfoBar(MyWindow);
}
}
pascal void DrawInfo(void *rect, const char *str, GrafPortPtr w)
{
if (str)
{
SetForeColor(0x00);
SetBackColor(0x0f);
MoveTo(8,22);
DrawString(str);
}
}
void DrawWindow(void)
{
DrawControls(GetPort());
}
// returns 1 on success, 0 on error.
Word LoadNDATools(void)
{
if (!QDAuxStatus() || _toolErr)
{
LoadOneTool(0x12,0);
if (_toolErr) return 0;
QDAuxStartUp();
FlagQDAux = true;
}
if (!FMStatus() || _toolErr)
{
Handle h;
LoadOneTool(0x1b, 0);
if (_toolErr) return 0;
HandleFM = NewHandle(MyID, 0x0100, 0xc005, 0);
if (_toolErr) return 0;
FMStartUp(MyID, (Word)*HandleFM);
FlagFM = true;
}
if (!TEStatus() || _toolErr)
{
LoadOneTool(0x22,0x0);
if (_toolErr) return 0;
HandleTE = NewHandle(MyID, 0x0100, 0xc005, 0);
if (_toolErr) return 0;
TEStartUp(MyID, (Word)*HandleTE);
FlagTE = true;
}
if (!SFStatus() || _toolErr)
{
LoadOneTool(0x17,0);
if (_toolErr) return 0;
HandleSF = NewHandle(MyID, 0x0100, 0xc005, 0);
if (_toolErr) return 0;
SFStartUp(MyID, (Word)*HandleSF);
FlagSF = true;
}
}
#pragma databank 0
GrafPortPtr NDAOpen(void)
{
Boolean ok = true;
const char *err = NULL;
if (!LoadNDATools())
{
AlertWindow(awCString, NULL,
(Ref)"24~Unable to load required tools.~^Too Bad");
return NULL;
}
LoadConfig(MyID);
// Check if Marinetti Active.
if (!TCPIPStatus() || _toolErr)
FlagTCP = false;
else FlagTCP = TCPIPGetConnectStatus();
if (ok)
{
Pointer myPath;
Word oldLevel;
Word oldPrefs;
Word oldRApp;
LevelRecGS levelDCB;
SysPrefsRecGS prefsDCB;
Handle H;
// load our resource. -- see TN.iigs #71
oldRApp = GetCurResourceApp();
ResourceStartUp(MyID);
myPath = LGetPathname2(MyID, 1);
levelDCB.pCount = 2;
GetLevelGS(&levelDCB);
oldLevel = levelDCB.level;
levelDCB.level = 0;
SetLevelGS(&levelDCB);
prefsDCB.pCount = 1;
GetSysPrefsGS(&prefsDCB);
oldPrefs = prefsDCB.preferences;
prefsDCB.preferences = (prefsDCB.preferences & 0x1fff) | 0x8000;
SetSysPrefsGS(&prefsDCB);
MyRID = OpenResourceFile(readEnable, NULL, myPath);
//
MyWindow = NewWindow2(NULL, 0, DrawWindow, NULL,
refIsResource, rQSWindow, rWindParam1);
SetInfoDraw(DrawInfo, MyWindow);
UpdateStatus(false);
AcceptRequests(ReqName, MyID, &HandleRequest);
SetSysWindow(MyWindow);
ShowWindow(MyWindow);
SelectWindow(MyWindow);
//
prefsDCB.preferences = oldPrefs;
SetSysPrefsGS(&prefsDCB);
levelDCB.level = oldLevel;
SetLevelGS(&levelDCB);
SetCurResourceApp(oldRApp);
return MyWindow;
}
return NULL;
}
void NDAClose(void)
{
// if running, shut down.
if (FlagQS) StopServer();
CloseWindow(MyWindow);
MyWindow = NULL;
AcceptRequests(ReqName, MyID, NULL);
UnloadConfig();
CloseResourceFile(MyRID);
ResourceShutDown();
}
void NDAInit(Word code)
{
if (code)
{
MyWindow = NULL;
FlagTCP = false;
FlagQS = false;
FlagQDAux = false;
FlagFM = false;
FlagTE = false;
FlagSF = false;
HandleFM = NULL;
HandleTE = NULL;
HandleSF = NULL;
FlagLoadTCP = false;
MyID = MMStartUp();
Ipid = 0;
MyRID = 0;
}
else
{
if (FlagLoadTCP && !TCPIPGetConnectStatus())
{
TCPIPShutDown();
UnloadOneTool(0x36);
}
if (FlagTE)
{
TEShutDown();
UnloadOneTool(0x22);
DisposeHandle(HandleTE);
}
if (FlagFM)
{
FMShutDown();
UnloadOneTool(0x1b);
DisposeHandle(HandleFM);
}
if (FlagQDAux)
{
QDAuxShutDown();
UnloadOneTool(0x12);
}
if (FlagSF)
{
SFShutDown();
UnloadOneTool(0x17);
DisposeHandle(HandleSF);
}
}
}
word NDAAction(void *param, int code)
{
word eventCode;
static EventRecord event = { 0 };
static word counter = 0;
if (code == runAction)
{
if (FlagQS) QServer();
return 1;
}
else if (code == eventAction)
{
BlockMove((Pointer)param, (Pointer)&event, 16);
event.wmTaskMask = 0x001FFFFF;
eventCode = TaskMasterDA(0, &event);
switch(eventCode)
{
case updateEvt:
BeginUpdate(MyWindow);
DrawWindow();
EndUpdate(MyWindow);
break;
case wInControl:
switch (event.wmTaskData4)
{
/* start marinetti */
case CtrlStartM:
//
// 1 load marinetti if need be.
if (!TCPIPStatus() || _toolErr)
{
LoadOneTool(0x36,0x0200);
TCPIPStartUp();
FlagLoadTCP = true;
}
if (TCPIPGetConnectStatus())
{
FlagTCP = true;
UpdateStatus(true);
}
else
{
TCPIPConnect(MarinettiCallback);
}
break;
/* stop marinetti */
case CtrlStopM:
if (!TCPIPGetConnectStatus())
{
FlagTCP = false;
UpdateStatus(true);
}
else
{
if (FlagQS) StopServer();
// if option key down, force a shutdown.
TCPIPDisconnect(event.modifiers & optionKey, MarinettiCallback);
}
break;
/* start the server */
case CtrlStartQS:
StartServer();
break;
/* stop the server */
case CtrlStopQS:
StopServer();
break;
case CtrlConfig:
DoConfig(MyID);
break;
}
// todo - Command-A selects all.
}
}
else if (code == copyAction)
{
TECopy(NULL);
return 1; // yes we handled it.
}
return 0;
}