diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..13e7564 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +o diff --git a/GNUmakefile b/GNUmakefile index c7d7974..637f589 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -1,17 +1,28 @@ -OBJ = o/main.a o/connection.a +BIN_OBJ = o/main.a o/connection.a +NDA_OBJ = o/nda.a o/connection.a o/tools.a - -dict : $(OBJ) +dict : $(BIN_OBJ) iix link o/main o/connection keep=$@ +dict.nda : $(NDA_OBJ) o/nda.r + iix link o/nda o/connection o/tools keep=$@ + iix copyfork o/nda.r $@ -r + iix chtyp -t nda $@ + o/main.a : main.c connection.h o/connection.a : connection.c connection.h +o/tools.a : tools.c +o/nda.a : nda.c nda.h +o/nda.r : nda.rez nda.h o : mkdir $@ o/%.a : %.c | o iix compile $< keep=o/$* + +o/%.r : %.rez | o + iix compile $< keep=$@ diff --git a/connection.c b/connection.c index f89e228..f983c4c 100644 --- a/connection.c +++ b/connection.c @@ -7,7 +7,6 @@ #include "connection.h" #include -//#include "s16debug.h" static char pstring[256]; @@ -106,9 +105,6 @@ Word ConnectionPoll(Connection *buffer) { if (terr || _toolErr) { // CloseAndLogout(buffer); - // s16_debug_printf("terr = %04x tool error = %04x\n", terr, _toolErr); - // s16_debug_srbuff(&sr); - TCPIPCloseTCP(buffer->ipid); TCPIPLogout(buffer->ipid); buffer->ipid = 0; @@ -126,8 +122,6 @@ Word ConnectionPoll(Connection *buffer) { if (sr.srState == TCPSCLOSED || sr.srState == TCPSTIMEWAIT) { - // s16_debug_srbuff(&sr); - TCPIPLogout(buffer->ipid); buffer->ipid = 0; buffer->state = kConnectionStateDisconnected; @@ -227,8 +221,7 @@ Word ConnectionClose(Connection *buffer) { buffer->terr = TCPIPCloseTCP(buffer->ipid); if (buffer->displayPtr) { - static char message[] = "\pClosing connection: $0000"; - Int2Hex(buffer->terr, message + 22, 4); + static char message[] = "\pClosing connection"; buffer->displayPtr(message); } return 0; @@ -247,3 +240,39 @@ Word ConnectionClose(Connection *buffer) { return -1; } + +Word ConnectionAbort(Connection *buffer) { + Word state = buffer->state; + + buffer->state = 0; + switch(state) { + case kConnectionStateDNR: + TCPIPCancelDNR(&buffer->dnr); + + if (buffer->displayPtr) { + static char message[] = "\pDNR lookup canceled"; + buffer->displayPtr(message); + } + return 1; + break; + + case kConnectionStateDisconnected: + return 1; + break; + + case 0: + return -1; + + default: + buffer->terr = TCPIPAbortTCP(buffer->ipid); + if (buffer->displayPtr) { + static char message[] = "\pClosing connection"; + buffer->displayPtr(message); + } + TCPIPLogout(buffer->ipid); + buffer->ipid = 0; + return 1; + + } + return -1; +} diff --git a/connection.h b/connection.h index 18a1908..b913592 100644 --- a/connection.h +++ b/connection.h @@ -32,6 +32,7 @@ Word ConnectionOpenC(Connection *, const char *host, Word port); Word ConnectionOpenGS(Connection *, const GSString255 *host, Word port); Word ConnectionClose(Connection *); +Word ConnectionAbort(Connection *); Word ConnectionPoll(Connection *); #endif diff --git a/nda.c b/nda.c new file mode 100644 index 0000000..63d8ff7 --- /dev/null +++ b/nda.c @@ -0,0 +1,419 @@ +#pragma nda NDAOpen NDAClose NDAAction NDAInit 30 0xffff "--Dictionary\\H**" +#pragma lint - 1 +#pragma optimize - 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "connection.h" +#include "nda.h" + +unsigned NDAStartUpTools(Word memID, StartStopRecord *ssRef); +void NDAShutDownTools(StartStopRecord *ssRef); + +typedef struct NDAResourceCookie { + Word oldPrefs; + Word oldRApp; + Word resFileID; +} NDAResourceCookie; + +void NDAResourceRestore(NDAResourceCookie *cookie); +void NDAResourceShutDown(NDAResourceCookie *cookie); +Word NDAResourceStartUp(Word memID, Word access, NDAResourceCookie *cookie); + +Word MyID; +Word ipid; +Word FlagTCP; +Word ToolsLoaded; +GrafPortPtr MyWindow; + +static StartStopRecord ss = {0, + 0, + 0, + 0, + 4, + { + 0x12, 0x0000, /* QD Aux */ + 0x1b, 0x0000, /* Font Manager */ + 0x22, 0x0000, /* Text Edit */ + 0x36, 0x0300, /* TCP */ + } + +}; + +static NDAResourceCookie resInfo; +static Connection connection; + +enum { + st_none, + st_init, + st_connect, + st_login, + st_client, + st_define1, + st_define2, + st_define3, + st_quit, + st_disconnect, +}; + +static unsigned st = 0; +static LongWord qtick = 0; +const char *ReqName = "\pTCP/IP~kelvin~dict~"; + +void InsertString(word length, char *cp) { + Handle handle; + // TERecord **temp; + longword oldStart, oldEnd; + + handle = (Handle)GetCtlHandleFromID(MyWindow, rCtrlTE); + // 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); +} + +static char buffer[512]; + +void TCPLoop(void) { + + static srBuff sr; + static rlrBuff rlr; + + Word terr; + unsigned x; + int status; + + switch (st) { + + case st_connect: + x = ConnectionPoll(&connection); + switch (x) { + case kConnectionStateConnected: + ++st; + break; + case kConnectionStateDisconnected: + case kConnectionStateError: + st = st_none; + break; + } + return; + case st_disconnect: + x = ConnectionPoll(&connection); + switch (x) { + case kConnectionStateDisconnected: + st = st_none; + break; + case kConnectionStateError: + st = st_none; + break; + } + return; + + case st_login: + case st_client: + case st_define1: + case st_define2: + case st_define3: + case st_quit: + TCPIPPoll(); + + sr.srRcvQueued = 0; + terr = TCPIPStatusTCP(ipid, &sr); + if (sr.srRcvQueued == 0) { + if (GetTick() >= qtick) { + /* timeout */ + } + return; + } + /* all data should be \r\n delimited. we want to keep the \r */ + terr = TCPIPReadLineTCP(ipid, "\p\n", 0x0000, (Ref)&buffer, + sizeof(buffer) - 2, &rlr); + if (!rlr.rlrIsDataFlag) + return; + + /* ensure a trailing \r and 0 */ + x = rlr.rlrBuffCount; + if (x) { + --x; + if (buffer[x] != '\r') { + buffer[x] = '\r'; + ++x; + } + ++x; + } + buffer[x] = 0; + ++x; + rlr.rlrBuffCount = x; + + if (st != st_define3) { + unsigned i; + status = 0; + for (i = 0;; ++i) { + unsigned c = buffer[i]; + if (isdigit(x)) { + status *= 10; + status += c - '0'; + continue; + } + if (isspace(c) || c == 0) + break; + status = -1; + break; + } + if (i == 0) + status = -1; + } + break; + } + + switch (st) { + case st_login: + /* expect a 220 status */ + if (status == 220) { + ++st; + terr = TCPIPWriteTCP(ipid, "CLIENT dict-nda-iigs\r\n", 22, 1, 0); + } + /* else error... */ + break; + case st_client: + /* expect 250 status */ + if (status == 250) { + ++st; + /* send define string... */ + } + /* else error */ + break; + case st_define1: + /* expect 550, 552, or 150 status */ + if (status == 150) { + ++st; + break; + } + + if (status == 552) { + InsertString(10, "No match\r"); + st = st_none; + } else { + InsertString(rlr.rlrBuffCount, buffer); + st = st_none; + } + break; + case st_define2: + /* expect 151 */ + if (status == 151) + ++st; + else if (status == 250) + st = st_none; + else { + } + break; + case st_define3: + /* expect definition text. '.' terminates. */ + if (buffer[0] == '.') { + InsertString(rlr.rlrBuffCount - 1, buffer + 1); + if (buffer[1] == '\r') { + --st; + } + } else { + InsertString(rlr.rlrBuffCount, buffer); + } + break; + + case st_quit: + /* expect 221 but doesn't really matter... */ + ConnectionClose(&connection); + st = st_disconnect; + break; + } +} + +// activate/inactivate controls based on Marinetti status +void UpdateStatus(Boolean redraw) { + if (FlagTCP) // TCP started + { + + SetInfoRefCon((LongWord) "\pNetwork Connected", MyWindow); + } else { + + SetInfoRefCon((LongWord) "\pNetwork Disconnected", MyWindow); + } + if (redraw) + DrawInfoBar(MyWindow); +} + +#pragma databank 1 + +/* + * Watch for TCP status updates. + */ +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) { + FlagTCP = false; + ipid = 0; + UpdateStatus(true); + } + SetCurResourceApp(oldRApp); +} + +pascal void MarinettiCallback(char *str) { + if (MyWindow) { + SetInfoRefCon((LongWord)str, MyWindow); + DrawInfoBar(MyWindow); + } +} + +pascal void DrawInfo(Rect *rect, const char *str, GrafPortPtr w) { + SetForeColor(0x00); + SetBackColor(0x0f); + EraseRect(rect); + if (str) { + MoveTo(/*8, 22*/ rect->h1 + 2, rect->v1 + 2); + DrawString(str); + } +} + +void DrawWindow(void) { DrawControls(GetPort()); } + +#pragma databank 0 + +void NDAInit(Word code) { + if (code) { + MyWindow = NULL; + FlagTCP = false; + ToolsLoaded = false; + + MyID = MMStartUp(); + ipid = 0; + } else { + if (ToolsLoaded) + NDAShutDownTools(&ss); + ToolsLoaded = false; + } +} + +void NDAClose(void) { + // if running, shut down. + + AcceptRequests(ReqName, MyID, NULL); + ConnectionAbort(&connection); + + CloseWindow(MyWindow); + MyWindow = NULL; + + NDAResourceShutDown(&resInfo); +} + +GrafPortPtr NDAOpen(void) { + + MyWindow = NULL; + + if (!ToolsLoaded) { + if (NDAStartUpTools(MyID, &ss)) { + NDAShutDownTools(&ss); + return NULL; + } + ToolsLoaded = true; + } + + if (TCPIPLongVersion() < 0x03006010) { + AlertWindow(awCString, NULL, + (Ref) "24~Marinetti 3.0b10 or newer required.~^Ok"); + return NULL; + } + + // Check if Marinetti Active. + FlagTCP = TCPIPGetConnectStatus(); + + if (NDAResourceStartUp(MyID, readEnable, &resInfo)) { + + MyWindow = NewWindow2(NULL, 0, DrawWindow, NULL, refIsResource, rWindow, + rWindParam1); + + SetInfoDraw(DrawInfo, MyWindow); + AcceptRequests(ReqName, MyID, &HandleRequest); + + SetSysWindow(MyWindow); + ShowWindow(MyWindow); + SelectWindow(MyWindow); + + ConnectionInit(&connection, MyID, MarinettiCallback); + + NDAResourceRestore(&resInfo); + return MyWindow; + } + return NULL; +} + +word NDAAction(void *param, int code) { + word eventCode; + static EventRecord event = {0}; + + if (code == runAction) { + if (st) + TCPLoop(); + 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 rCtrlDefine: { + + break; + } + } + // todo - Command-A selects all. + } + } else if (code == copyAction) { + TECopy(NULL); + return 1; // yes we handled it. + } + + return 0; +} \ No newline at end of file diff --git a/nda.h b/nda.h new file mode 100644 index 0000000..4fb9879 --- /dev/null +++ b/nda.h @@ -0,0 +1,6 @@ +/* used by C and Rez */ + +#define rCtrlLE 1 +#define rCtrlDefine 2 +#define rCtrlTE 3 +#define rWindow 0xFF8 diff --git a/nda.rez b/nda.rez new file mode 100644 index 0000000..77b1fcb --- /dev/null +++ b/nda.rez @@ -0,0 +1,131 @@ +#include "Types.rez" +#include "nda.h" + +resource rControlList (rWindow) { + { + rCtrlLE, + rCtrlDefine, + rCtrlTE, + } +}; + +resource rControlTemplate (rCtrlLE) { + rCtrlLE, + {10, 10, 23, 414}, + editLineControl { + { /* optional Fields */ + 0x0, + 0x7002, + 0x1, + 50, + 0x1000D + } + } +}; + +resource rControlTemplate (rCtrlDefine) { + rCtrlDefine, + {10, 440, 23, 530}, + SimpleButtonControl { + { /* optional Fields */ + SquareShadowButton, + 0x3002, + 0x2, + 0x1000C, + 0x0, + { + "\n", + "\n", + 0x0, + 0x0 + } + } + } +}; + +resource rControlTemplate (rCtrlTE) { + rCtrlTE, + {26, -2, 134, 544}, + editTextControl { + { /* optional Fields */ + 0x0, + 0x7400, + 0x3, + 0x27A80000, + {-1, -1, -1, -1}, + 0xFFFFFFFF, + 0, + 0x0, + 0, + 0x0, + 0x15, + 0x4, + 0, + 0, + 0, + 0, + 0, + 0x0, + 0x0, + 0x0 + } + } +}; + +/* Button title */ +resource rPString (0x1000C) { + "Define" +}; + +/* Line Edit text */ +resource rPString (0x1000D) { + "" +}; + +/* Window title */ +resource rPString (0x1000E) { + "Dict" +}; + +resource rWindParam1 (rWindow) { + fClose + fTitle + fMove + fInfo, //0xC0B0, + 0x1000E, + 0x0, + {0, 0, 0, 0}, + 0x0, // rWindColor + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + {0, 0}, + 0x0, + 13, // info height + {51, 48, 184, 590}, + infront, + rWindow, // rControlList + 0x209 +}; + +/* TE Control text */ +resource rText (0x4) { + "" +}; + +resource rComment (1) { + "Dict NDA\n\n" + "Written by Kelvin W Sherlock\n" + "November/December 2018." +}; + +resource rVersion (1) { + { + 1, + 0, + 0, + alpha, + 0 + }, + verUS, + "Dict", + "(C) 2018 Kelvin Sherlock " +};