#include #include #include #include #include #include #define MAX_CHARS 102 #define SECSIZ 0x80 #define TTIME 30 #define BufSize 0x1000 #define ERRORMAX 10 #define RETRYMAX 10 #define SOH 1 #define EOT 4 #define ACK 6 #define CTRLQ (char)17 #define CTRLS (char)19 #define NAK 21 static char bufr[BufSize]; static int fd, timeout = FALSE; static long bytes_xferred; static int oktosay = 1; /* * External functions */ extern unsigned char *stpblk(); extern unsigned char *AllocMem(); extern struct MsgPort *CreatePort(); extern struct FileHandle *Open(); /* * forward references */ int define_function_key(), end(), help(), offline(), online(), sb(), rb(), gfxoff(), speechon(), speechoff(); /* * Tables */ struct { unsigned char *cmdname; int (*cmdfunc)(); } command_table[] = { (unsigned char *)"define", &define_function_key, (unsigned char *)"def", &define_function_key, (unsigned char *)"end", &end, (unsigned char *)"help", &help, (unsigned char *)"online", &online, (unsigned char *)"on", &online, (unsigned char *)"offline", &offline, (unsigned char *)"off", &offline, (unsigned char *)"gfxoff", &gfxoff, (unsigned char *)"sb", &sb, (unsigned char *)"rb", &rb, (unsigned char *)"speechon", &speechon, (unsigned char *)"speechoff", &speechoff, (unsigned char *)"\0", &help, }; unsigned char *help_messages[] = { "sb = send file using Xmodem", "rb = receive file using Xmodem", "def = define a function key", "define = define a function key", "end = exit the program", "help = print this list", "online = enter or re-enter terminal mode", "offline = terminate communication", "gfxoff = terminate graphics", "speechon = permit speech", "speechoff = forbid speech", 0}; unsigned char *function_key_definitions[20] = { 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0 }; /* * Globals */ unsigned char work[512]; unsigned char buf[512]; unsigned char iobuf[1024]; int num_of_chars, no_io; /* * Terminal globals */ struct FileHandle *terminal_infp; struct FileHandle *terminal_outfp; /* * Terminal emulator stuff */ struct Message *mymessage; struct IOExtSer *ModemReadRequest; struct IOExtSer *ModemWriteRequest; unsigned char *WelcomeMessage = "Entering Terminal Mode\nUse ^C for command mode\n"; unsigned char *GoodbyeMessage = "Disconnected\n"; unsigned char *OfflineMessage = "--- Offline ---\n"; unsigned char *OnlineMessage = "--- Online ---\n"; unsigned char rs_in[2], rs_out[2]; int bdoneflag = 0; int TermEcho = 0; int modem_online = 0; static int gfx_flag; main(argc, argv) int argc; unsigned char *argv[]; { gfx_flag = 0; num_of_chars = 0; no_io = 0; sprintf(work, "Raw:0/0/640/200/Terminal"); terminal_infp = Open(work, MODE_NEWFILE); if (terminal_infp == 0) { printf("Can't open window\n"); exit(1); } terminal_outfp = terminal_infp; sprintf(work, "\033[0x\033[0y\033[25t\033[80u\014"); WriteWork(); while (1) { Write(terminal_outfp, "\033[7mterm:\033[m ", 13); getcommand(buf); CommandInterpreter(buf); } } WriteWork() { Write(terminal_outfp, work, strlen(work)); } CommandInterpreter(command) unsigned char *command; { int i; command = stpblk(command); /* * Scan through the command table for the string and invoke the function * to do the actual work of the command. Each of these commands is * defined below, and the functions each take a pointer to the * string containing the arguments passed the command line. */ for (i=0; command_table[i].cmdname[0] != '\0'; i++) if (strncmp(command, command_table[i].cmdname, strlen(command_table[i].cmdname)) == 0) { (*command_table[i].cmdfunc) (stpblk(&command[strlen(command_table[i].cmdname)])); goto FinishedCommand; } /* * Not found, so look for it on the disk. */ executive(stpblk(&command[0])); FinishedCommand: ; /* Labels MUST be attached to some statement; even if the null stmt */ } executive(s) unsigned char *s; { if (!Execute(s, 0, terminal_outfp)) printf("%d\n", IoErr()); } define_function_key(s) unsigned char *s; { int i; if (s[0] == '\0') for (i=0; i<20; i++) { if (function_key_definitions[i]) { sprintf(work, "F%-2d = %s\n", i+1, function_key_definitions[i]); WriteWork(); } } else if (s[0] == 'f' || s[0] == 'F') { s++; i = atoi(s); if (i < 1 || i > 20) { sprintf(work, "%c[36mInvalid function key%c[0m\n", 0x1b, 0x1b); WriteWork(); } else { i--; if (function_key_definitions[i]) FreeMem(function_key_definitions[i], strlen(function_key_definitions[i])+1); while (isdigit(*s)) s++; s = stpblk(s); if (*s != '\0') { function_key_definitions[i] = AllocMem(strlen(s)+1, MEMF_PUBLIC|MEMF_CLEAR); if (function_key_definitions[i] == 0) { sprintf(work, "%c[36mDefine Error: not enough memory%c[0m\n", 0x1b, 0x1b); WriteWork(); } else strcpy(function_key_definitions[i], s); } } } else { sprintf(work, "%c[36mDefine Error: invalid function key specified%c[0m\n", 0x1b, 0x1b); WriteWork(); } } end(s) unsigned char *s; { if (modem_online) { sprintf(work, "%c[36mTerminal Mode Error: Modem still online%c[0m\n", 0x1b, 0x1b); WriteWork(); } else { if (gfx_flag == 1) terminate(); Close(terminal_outfp); exit(0); } } help(s) unsigned char *s; { int i; sprintf(work,"%c[7m MyCli Help %c[0m\n", 0x1b, 0x1b); WriteWork(); for (i=0; help_messages[i]; i++) { sprintf(work, "%s\n", help_messages[i]); WriteWork(); } sprintf(work, "%c[7m End of Help %c[0m\n", 0x1b, 0x1b); WriteWork(); } gfxoff() { if (gfx_flag == 1) terminate(); gfx_flag = 0; } speechon() { oktosay = 1; } speechoff() { oktosay = 0; } offline(s) unsigned char *s; { modem_online = 0; say_string((char*)0, 1); } online(s) unsigned char *s; { modem_online = !0; /* signal that modem is live !!! */ if (initialize()) { /* set baud rate, etc. */ Write(terminal_outfp, WelcomeMessage, strlen(WelcomeMessage)); while (modem_online) { bdoneflag = 0; /* terminal mode on flag */ Write(terminal_outfp, OnlineMessage, strlen(OnlineMessage)); while (!bdoneflag) { check_keyboard(); check_modem(); if (bdoneflag || num_of_chars > MAX_CHARS || no_io > 0) { if (num_of_chars > 0) { Write(terminal_outfp, iobuf, num_of_chars); num_of_chars = 0; } } } Write(terminal_outfp, OfflineMessage, strlen(OfflineMessage)); Write(terminal_outfp, "\033[7mterm:\033[m ", 13); getcommand(buf); CommandInterpreter(buf); } cleanup(); } modem_online = 0; } getcommand(s) unsigned char *s; { unsigned char c; unsigned col; col = 0; while (1) { Read(terminal_infp, &c, 1); switch(c) { case 8: if (col) { c = 8; Write(terminal_outfp, &c, 1); c = ' '; Write(terminal_outfp, &c, 1); c = 8; Write(terminal_outfp, &c, 1); col--; } continue; case 10: case 13: sprintf(work, "\n"); WriteWork(); s[col++] = '\0'; break; case 0x1b: case 24: while (col) { c = 8; Write(terminal_outfp, &c, 1); c = ' '; Write(terminal_outfp, &c, 1); c = 8; Write(terminal_outfp, &c, 1); col--; } continue; case 0x9b: if (process_event(&s[col])) { strcat(s, "\n"); Write(terminal_outfp, &s[col], strlen(&s[col])); break; } continue; default: s[col++] = c; Write(terminal_outfp, &c, 1); continue; } break; } } /* * this function converts an incoming ANSI escape sequence * and processes it. A buffer is passed where any function * key expansion is to take place. If the buffer is modified * for any reason, this function returns true. */ process_event(cmd_line) unsigned char *cmd_line; { int i; unsigned char c; char event_buffer[32]; i = 0; while (1) { Read(terminal_infp, &c, 1); event_buffer[i] = c; if (c == '~' || c == '|' || c == 'A' || c == 'B' || c == 'C' || c == 'D') break; i++; } event_buffer[i+1] = '\0'; if (event_buffer[i] == '~') { if (event_buffer[0] == '?') { strcpy(cmd_line, "help"); return !0; } else if (isdigit(event_buffer[0])) { if (function_key(atoi(event_buffer), cmd_line)) return !0; else if (atoi(event_buffer) == 6) bdoneflag = !0; } } else if (i == 0 && (event_buffer[0] >= 'A' && event_buffer[0] <= 'D')) { cmd_line[0] = '\033'; cmd_line[1] = event_buffer[0]; cmd_line[2] = '\000'; return !0; } return 0; } /* * if a definition for the function key fkey exists (0-19), then * the translation for the function key is copied to the string * s, and this function returns !0. Otherwise, now translation * exists, and this function returns 0. */ function_key(fkey, s) int fkey; unsigned char *s; { int i; if (function_key_definitions[fkey] != 0) { for (i=0; function_key_definitions[fkey][i] != '\0'; i++) s[i] = function_key_definitions[fkey][i]; s[i] = '\0'; return !0; } return 0; } initialize() { ModemReadRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemReadRequest), MEMF_PUBLIC | MEMF_CLEAR); ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemReadRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Read_RS",0); if (OpenDevice(SERIALNAME, NULL, ModemReadRequest, NULL)) { sprintf(work, "%c[36mCan't open serial read device%c[0m\n", 0x1b, 0x1b); WriteWork(); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); return 0; } ModemReadRequest->IOSer.io_Command = CMD_READ; ModemReadRequest->IOSer.io_Length = 1; ModemReadRequest->IOSer.io_Data = (APTR) &rs_in[0]; ModemWriteRequest = (struct IOExtSer *)AllocMem(sizeof(*ModemWriteRequest), MEMF_PUBLIC | MEMF_CLEAR); ModemWriteRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemWriteRequest->IOSer.io_Message.mn_ReplyPort = CreatePort("Write_RS",0); if (OpenDevice(SERIALNAME, NULL, ModemWriteRequest, NULL)) { sprintf(work, "%c[36mCan't open serial write device%c[0m\n", 0x1b, 0x1b); WriteWork(); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest)); return 0; } ModemWriteRequest->IOSer.io_Command = CMD_WRITE; ModemWriteRequest->IOSer.io_Length = 1; ModemWriteRequest->IOSer.io_Data = (APTR) &rs_out[0]; ModemReadRequest->io_SerFlags = SERF_SHARED | SERF_XDISABLED; ModemReadRequest->io_Baud = 1200; ModemReadRequest->io_ReadLen = 8; ModemReadRequest->io_WriteLen = 8; ModemReadRequest->io_CtlChar = 1L; ModemReadRequest->IOSer.io_Command = SDCMD_SETPARAMS; DoIO(ModemReadRequest); ModemReadRequest->IOSer.io_Command = CMD_READ; BeginIO(ModemReadRequest); return !0; } cleanup() { CloseDevice(ModemReadRequest); DeletePort(ModemReadRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemReadRequest, sizeof(*ModemReadRequest)); CloseDevice(ModemWriteRequest); DeletePort(ModemWriteRequest->IOSer.io_Message.mn_ReplyPort); FreeMem(ModemWriteRequest, sizeof(*ModemWriteRequest)); Write(terminal_outfp, GoodbyeMessage, strlen(GoodbyeMessage)); } check_keyboard() { unsigned char *pc; if (WaitForChar(terminal_infp, 1)) { Read(terminal_infp, &rs_out[0], 1); switch ((unsigned char)rs_out[0]) { case 0x9b: /* ANSI keyboard stuff */ if (process_event(&buf[0])) { /* send the translation */ pc = &buf[0]; while (*pc != '\0') { rs_out[0] = *pc++; if (TermEcho) Write(terminal_outfp, &rs_out[0], 1); DoIO(ModemWriteRequest); check_modem(); } } break; case 0x05: /* toggle keystroke echo */ TermEcho = !TermEcho; sprintf(work, "%c[36mEcho %s%c[0m\n", 0x1b, TermEcho?"ON":"OFF", 0x1b); WriteWork(); break; default: if (TermEcho) Write(terminal_outfp, &rs_out[0], 1); DoIO(ModemWriteRequest); } } } /* * Check to see if the Read Request IO has completed from the modem. */ check_modem() { static int sayflag = 0; static char saystring[133]; static int sayind = 0; static int escape_sequence = 0; if (CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); rs_in[0] &= 0x7f; if (rs_in[0] == '\001' && oktosay == 1) { sayflag = 1; BeginIO(ModemReadRequest); return; } if (oktosay == 1 && sayflag) { if (rs_in[0] >= ' ' && rs_in[0] < (char)127) { saystring[sayind++] = rs_in[0]; } else { Write(terminal_outfp, iobuf, num_of_chars); rs_out[0] = CTRLS; DoIO(ModemWriteRequest); num_of_chars = 0; saystring[sayind++] = (char)0; say_string(saystring,0); sayind = 0; sayflag = 0; rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); } } if (rs_in[0] == '\033') { escape_sequence = 1; } else if (escape_sequence == 1) { if (rs_in[0] == 'G') { Graphics(); } else { iobuf[num_of_chars++] = '\033'; iobuf[num_of_chars++] = rs_in[0]; no_io = 0; } escape_sequence = 0; } else { iobuf[num_of_chars++] = rs_in[0]; no_io = 0; } BeginIO(ModemReadRequest); } else { no_io++; } } sendchar(ch) int ch; { rs_out[0] = ch; DoIO(ModemWriteRequest); } readchar() { unsigned char c; int rd,ch; rd = FALSE; while (rd == FALSE) { if(CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); ch=rs_in[0]; rd = TRUE; BeginIO(ModemReadRequest); } } if (rd == FALSE) { timeout = TRUE; emits("\nTimeout Waiting For Character\n"); } c = ch; return(c); } rb(file) char *file; { int firstchar, sectnum, sectcurr, sectcomp, errors, errorflag; unsigned int checksum, j, bufptr,i; char numb[10]; bytes_xferred = 0L; i = 10; if ((fd = creat(file, 0)) < 0) { emits("Cannot Open File\n"); return FALSE; } else emits("Receiving File\n"); timeout=FALSE; sectnum = errors = bufptr = 0; sendchar(NAK); firstchar = 0; while (firstchar != EOT && errors != ERRORMAX) { errorflag = FALSE; do { firstchar = readchar(); if (timeout == TRUE) return FALSE; } while (firstchar != SOH && firstchar != EOT); if (firstchar == SOH) { emits("Getting Block "); stci_d(numb,sectnum,i); emits(numb); emits("..."); sectcurr = readchar(); if (timeout == TRUE) return FALSE; sectcomp = readchar(); if (timeout == TRUE) return FALSE; if ((sectcurr + sectcomp) == 255) { if (sectcurr == (sectnum + 1 & 0xff)) { checksum = 0; for (j = bufptr; j < (bufptr + SECSIZ); j++) { bufr[j] = readchar(); if (timeout == TRUE) return FALSE; checksum = (checksum + bufr[j]) & 0xff; } if (checksum == readchar()) { errors = 0; sectnum++; bufptr += SECSIZ; bytes_xferred += SECSIZ; emits("verified\n"); if (bufptr == BufSize) { bufptr = 0; if (write(fd, bufr, BufSize) == EOF) { emits("\nError Writing File\n"); return FALSE; }; }; sendchar(ACK); } else { errorflag = TRUE; if (timeout == TRUE) return FALSE; } } else { if (sectcurr == (sectnum & 0xff)) { emits("\nReceived Duplicate Sector\n"); sendchar(ACK); } else errorflag = TRUE; } } else errorflag = TRUE; } if (errorflag == TRUE) { errors++; emits("\nError\n"); sendchar(NAK); } }; if ((firstchar == EOT) && (errors < ERRORMAX)) { sendchar(ACK); write(fd, bufr, bufptr); write(fd, "\n", 1); close(fd); return TRUE; } return FALSE; } sb(file) char *file; { int sectnum, bytes_to_send, size, attempts, c, i; unsigned checksum, j, bufptr; char numb[10]; timeout=FALSE; bytes_xferred = 0; i = 10; if ((fd = open(file, 1)) < 0) { emits("Cannot Open Send File\n"); return FALSE; } else emits("Sending File\n"); attempts = 0; sectnum = 1; j=1; while (((c = readchar()) != NAK) && (j++ < ERRORMAX)); if (j >= (ERRORMAX)) { emits("\nReceiver not sending NAKs\n"); return FALSE; }; while ((bytes_to_send = read(fd, bufr, BufSize)) && attempts != RETRYMAX) { if (bytes_to_send == EOF) { emits("\nError Reading File\n"); return FALSE; }; bufptr = 0; while (bytes_to_send > 0 && attempts != RETRYMAX) { attempts = 0; do { sendchar(SOH); sendchar(sectnum); sendchar(~sectnum); checksum = 0; size = SECSIZ <= bytes_to_send ? SECSIZ : bytes_to_send; bytes_to_send -= size; for (j = bufptr; j < (bufptr + SECSIZ); j++) if (j < (bufptr + size)) { sendchar(bufr[j]); checksum += bufr[j]; } else { sendchar(0); } sendchar(checksum & 0xff); attempts++; c = readchar(); if (timeout == TRUE) return FALSE; } while ((c != ACK) && (attempts != RETRYMAX)); bufptr += size; bytes_xferred += size; emits("Block "); stci_d(numb,sectnum,i); emits(numb); emits(" sent\n"); sectnum++; } } close(fd); if (attempts == RETRYMAX) { emits("\nNo Acknowledgment Of Sector, Aborting\n"); return FALSE; } else { attempts = 0; do { sendchar(EOT); attempts++; } while ((readchar() != ACK) && (attempts != RETRYMAX) && (timeout == FALSE)); if (attempts == RETRYMAX) emits("\nNo Acknowledgment Of End Of File\n"); }; return TRUE; } emits(embuf) char *embuf; { Write(terminal_outfp, embuf, strlen(embuf)); } Graphics() { char buf[82], *gr_buf; int gr_len, r, g, b, color, x1, y1, x2, y2; int polx[256], poly[256], n, clip, xmin, ymin, xmax, ymax; int i; if (gfx_flag == 0) { gfx_flag = 1; initialise(); } else get_screen(); rs_out[0] = CTRLS; DoIO(ModemWriteRequest); BeginIO(ModemReadRequest); for(;;) { gr_len = 0; buf[0] = (char)0; gr_buf = &(buf[1]); while(gr_buf[gr_len-1] != '\015') { if (CheckIO(ModemReadRequest)) { WaitIO(ModemReadRequest); rs_in[0] &= 0x7f; if (rs_in[0] != '\012') { gr_buf[gr_len++] = rs_in[0]; } BeginIO(ModemReadRequest); } else { rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); } } rs_out[0] = CTRLS; DoIO(ModemWriteRequest); gr_buf[gr_len-1] = (char)0; switch (gr_buf[0]) { case 'T': /* terminate(); */ put_screen(); rs_out[0] = CTRLQ; DoIO(ModemWriteRequest); return; case 'C': sscanf(&(gr_buf[1]), "%d%d%d%d", &color, &r, &g, &b); define_color(color, r, g, b); if (check_user_action() == -1) { put_screen(); return; } break; case 'L': sscanf(&(gr_buf[1]), "%d%d%d%d%d", &x1, &y1, &x2, &y2, &color); draw(x1, y1, x2, y2, color); if (check_user_action() == -1) { put_screen(); return; } break; case 'P': sscanf(&(gr_buf[1]), "%d%d%d%d%d%d%d", &n, &color, &clip, &xmin, &ymin, &xmax, &ymax); for (i=0; i