#pragma optimize 79 #pragma lint - 1 #include #include #include #include #include #include #include #include #include "connection.h" #define IncBusy() asm { jsl 0xE10064} #define DecBusy() asm { jsl 0xE10068} #define Resched() asm { cop 0x7f} #define BusyFlag ((byte *)0xE100FFl) unsigned d_flag = 0; // startup/shutdown flags. enum { kLoaded = 1, kStarted = 2, kConnected = 4, kLoadError = -1, kVersionError = -2 }; int StartUpTCP(displayPtr fx) { word status; word flags = 0; // TCPIP is an init, not a tool, so it should always // be loaded. status = TCPIPStatus(); if (_toolErr) { LoadOneTool(54, 0x0300); if (_toolErr == toolVersionErr) return kVersionError; if (_toolErr) return kLoadError; status = 0; flags |= kLoaded; } // require 3.0b11 if (TCPIPLongVersion() < 0x03006011) { if (flags & kLoaded) UnloadOneTool(54); return kVersionError; } if (!status) { TCPIPStartUp(); if (_toolErr) return kLoadError; flags |= kStarted; } status = TCPIPGetConnectStatus(); if (!status) { TCPIPConnect(fx); flags |= kConnected; } return flags; } void ShutDownTCP(int flags, Boolean force, displayPtr fx) { if (flags <= 0) return; if (flags & kConnected) { TCPIPDisconnect(force, fx); if (_toolErr) return; } if (flags & kStarted) { TCPIPShutDown(); if (_toolErr) return; } if (flags & kLoaded) { UnloadOneTool(54); } } // #pragma databank [push | pop] would be nice... #pragma databank 1 pascal void DisplayCallback(const char *message) { unsigned length; if (!d_flag) return; // message is a p-string. length = message ? message[0] : 0; if (!length) return; fprintf(stderr, "%.*s\n", length, message + 1); } #pragma databank 0 int ConnectLoop(char *host, Word port, Connection *connection) { LongWord qtick; ConnectionInit(connection, MMStartUp(), DisplayCallback); ConnectionOpenC(connection, host, port); // 30 second timeout. qtick = GetTick() + 30 * 60; while (!ConnectionPoll(connection)) { if (GetTick() >= qtick) { fputs("Connection timed out.\n", stderr); IncBusy(); TCPIPAbortTCP(connection->ipid); TCPIPLogout(connection->ipid); DecBusy(); return 0; } } if (connection->state != kConnectionStateConnected) { fprintf(stderr, "Unable to open host: %s:%u\n", host, port); return 0; } return 1; } int CloseLoop(Connection *connection) { ConnectionClose(connection); while (!ConnectionPoll(connection)) ; // wait for it to close. return 1; } static char buffer[512]; int ReadLineSync(word ipid) { LongWord qtick; static srBuff sr; static rlrBuff rlr; unsigned x; word terr; // asm { brk 0xea } buffer[0] = 0; qtick = GetTick() + 30 * 60; for (;;) { Word terr; TCPIPPoll(); terr = TCPIPStatusTCP(ipid, &sr); if (sr.srRcvQueued) break; if (terr) return -1; if (GetTick() >= qtick) { fputs("Read timed out.\n", stderr); return -1; } } for (;;) { terr = TCPIPReadLineTCP(ipid, "\p\r\n", 0x0000, (Ref)&buffer, sizeof(buffer) - 1, &rlr); if (terr) return -1; /* nb - marinetti < 3.0b11 return value inaccurate */ if (!rlr.rlrIsDataFlag) { if (GetTick() >= qtick) { fputs("Read timed out.\n", stderr); return -1; } TCPIPPoll(); continue; } break; } x = rlr.rlrBuffCount; buffer[x] = 0; return x; } int status(void) { unsigned x; if (sscanf(buffer, "%u", &x) == 1) { if (d_flag) fprintf(stderr, "status: %d\n", x); return x; } return -1; } int client(word ipid) { word terr; int ok; /* also checks for 220 header. */ ok = ReadLineSync(ipid); if (ok < 0) return ok; ok = status(); if (ok != 220) return -1; terr = TCPIPWriteTCP(ipid, "CLIENT dict-iigs\r\n", 18, 1, 0); if (terr != 0) fprintf(stderr, "terr: %04x\n", terr); ok = ReadLineSync(ipid); if (ok < 0) return ok; /* 3.6.2. Responses 250 ok (optional timing information here) */ ok = status(); if (ok != 250) return -1; return 0; } int quit(word ipid) { word terr; int ok; terr = TCPIPWriteTCP(ipid, "QUIT\r\n", 6, 1, 0); if (terr != 0) fprintf(stderr, "terr: %04x\n", terr); ok = ReadLineSync(ipid); if (ok < 0) return ok; /* 3.9.2. Responses 221 Closing Connection */ return 0; } int one_def(Word ipid) { int ok; for (;;) { ok = ReadLineSync(ipid); if (ok < 0) return ok; ok = status(); if (ok == 250) return 0; if (ok != 151) return -1; for (;;) { ok = ReadLineSync(ipid); if (ok < 0) return ok; if (buffer[0] == '.') { fputc('\n', stdout); break; } fputs(buffer, stdout); fputc('\n', stdout); } } fputc('\n', stdout); return 0; } int define(Word ipid, const char *term, const char *dict) { word terr; int ok; unsigned x; static char buffer[512]; if (!dict || !*dict) dict = "!"; if (!term || !*term) return -1; x = sprintf(buffer, "DEFINE %s \"%s\"\r\n", dict, term); terr = TCPIPWriteTCP(ipid, buffer, x, 1, 0); if (terr != 0) fprintf(stderr, "terr: %04x\n", terr); /* 3.2.2. Responses 550 Invalid database, use "SHOW DB" for list of databases 552 No match 150 n definitions retrieved - definitions follow 151 word database name - text follows 250 ok (optional timing information here) */ ok = ReadLineSync(ipid); if (ok < 0) return ok; ok = status(); switch (status()) { default: return -1; case 550: fputs("Invalid database.\n", stderr); return -1; case 552: fputs("No match.\n", stderr); return 0; case 150: return one_def(ipid); } } int main(int argc, char **argv) { Connection connection; int mf; int ok; word terr; --argc; ++argv; d_flag = 0; for (; argc; --argc, ++argv) { unsigned char c = **argv; if (c != '-') break; if (!strcmp(*argv, "-d")) { d_flag = 1; continue; } } if (argc < 1) { fputs("Usage: dict [-d] word...\n", stderr); exit(1); } mf = StartUpTCP(DisplayCallback); if (mf < 0) { fputs("Marinetti 3.0b11 or greater is required.\n", stderr); exit(1); } ok = ConnectLoop("dict.org", 2628, &connection); if (ok) { unsigned i; int ok; ok = client(connection.ipid); if (ok == 0) { for (i = 0; i < argc; ++i) { ok = define(connection.ipid, argv[i], NULL); if (ok < 0) break; } } quit(connection.ipid); CloseLoop(&connection); } ShutDownTCP(mf, false, DisplayCallback); return 0; }