This is Escaper.m in view mode; [Download] [Up]
#import "Escaper.h" #import "Term.h" #import "Modem.h" #import "Source.h" #import "StringResponder.h" #import "Fdset.h" #import <stdio.h> #import <ctype.h> #import <libc.h> #define MAXARGS 10 #define stripNL(temp) if (temp[strlen(temp)-1] == '\n') temp[strlen(temp)-1] = 0; struct scriptCommand { char *cmd; enum escapeFunction func; }; static struct scriptCommand decode[] = { {"nop",nop}, {"stop",stop}, {"protocol", protocol}, {"parity",parity}, {"send",sendfile}, {"receive",receivefile}, {"capture",capture}, {"hangup",hangup}, {"baudrate",baudrate}, {"echo",echo}, {"say",say}, {"expect",expect}, {"dial",dial}, {"readscript",readscript} }; #define NUL '\0' void breakIntoWords(char *line, char *words[]) { char *p = line; int i; for(i=0; *p; i++) { while( *p && isspace(*p)) p++; if (*p == NUL) break; words[i]=p; while( *p && !isspace(*p)) p++; if (*p) *p++ = NUL; } words[i]=NULL; } int member(int ch, char * set) { return(strchr(set,ch) != 0); } @implementation Escaper + newEscaperWithTerm:(id)t andModem:(id)m { int i; self = [super new]; term = t; modem = m; for (i=0; i<128; i++) keymap[i]=nop; keymap['b']=baudrate; keymap['d']=dial; keymap[CTRL('d')]=stop; keymap['p']=protocol; keymap[CTRL('p')]=parity; keymap['s']=sendfile; keymap['r']=receivefile; keymap['c']=capture; keymap['h']=hangup; keymap['e']=readscript; // for (e)xecute script file return self; } - readScript:(char *)file { FILE *fin; char line[200], *args[MAXARGS]; int i; id source; fin = fopen(file,"r"); if (fin==NULL) { sprintf(line,"couldn't open script file %s\n",file); [term putString:line]; return nil; } while (fgets(line,sizeof(line),fin)) { breakIntoWords(line,args); if (args[0]==NULL || *args[0]=='%') continue; // % is for comments for(i=0; i<sizeof(decode)/sizeof(decode[0]); i++) { if (strcmp(args[0],decode[i].cmd) == 0) { // then we found a command source = [Source newStrings:args+1]; [self doFunction:decode[i].func withInput:source]; } } } return self; } - doFunction:(enum escapeFunction) func withInput:(id)source { char temp[200]; switch (func) { case dial: { char dialPrefix[]="ATDT", dialPostfix[]="\r"; // constants for now; later local var's of modem char pn[200]; [source getline:pn size:sizeof(pn) WithPrompt:"Enter phone number:"]; sprintf(temp,"%s%s%s\n",dialPrefix, pn, dialPostfix); [self autoDial:temp]; break; } case baudrate: { int bps; [source getline:temp size:sizeof(temp) WithPrompt:"Enter new baud rate [300,1200,2400,4800,9600]:"]; sscanf(temp,"%d",&bps); [modem setSpeed:bps]; sprintf(temp,"Modem speed set to %d\n",[modem getSpeed]); [term putString:temp]; break; } case readscript: [source getline:temp size:sizeof(temp) WithPrompt:"Enter script file:"]; stripNL(temp); [self readScript:temp]; break; case stop: [term reset]; [modem endCapture]; [term putString:"\nquitting \n"]; exit(0); break; case protocol: { enum direction dir; char p; do { p = [source getcharWithPrompt:"\nEnter direction [(s)end,(r)eceive]:"]; } while (!member(p,"sr")); dir = (p=='s')?tohost:fromhost; sprintf(temp, "\nEnter desired %s protocol [(x)modem,xmodem(1)k,(y)modem,(z)modem]:", (dir==tohost)?"send":"receive"); do { p = [source getcharWithPrompt:temp]; } while (!member(p,"x1yz")); [modem setProtocol:p dir:dir]; sprintf(temp,"\nSend protocol is %c\n",[modem getProtocolDir:tohost]); [term putString:temp]; sprintf(temp,"\nReceive protocol is %c\n",[modem getProtocolDir:fromhost]); [term putString:temp]; break; } case parity: { int par, parity; do { par = [source getcharWithPrompt:"\nEnter desired parity (even, odd, or none) [e,o,n]:"]; if (par=='e' || par=='E') parity=EVENP; else if (par=='o' || par=='O') parity=ODDP; else if (par=='n' || par=='N') parity=NOPARITY; else parity=ILLEGAL_PARITY; } while (parity == ILLEGAL_PARITY); [modem setParity:parity]; sprintf(temp,"\nParity is %c\n",par); [term putString:temp]; break; } case sendfile: { char trigger[100]; struct stat dummy; int cc; do { [source getline:temp size:sizeof(temp) WithPrompt:"\nEnter file to send:"]; stripNL(temp); // check for existence of file if ((cc = stat(temp, &dummy)) != 0) [source putString:"Couldn't open file...try again"]; } while (temp[0] && cc != 0); // null filename means abort command if (temp[0]) { [source getline:trigger size:sizeof(trigger) WithPrompt:"\nEnter command to send to host:"]; [[term pushState] reset]; [modem writeOut:trigger]; [modem sendFile:temp]; [term popState]; } break; } case receivefile: [[term pushState] reset]; [modem receive]; [term popState]; break; case capture: if ([modem isCapturing]) { [term putString:"Ending capture to file\n"]; [modem endCapture]; } else { [source getline:temp size:sizeof(temp) WithPrompt:"\nEnter file to save to [tip.record]:"]; stripNL(temp); if (*temp == 0) strcpy(temp,"tip.record"); [modem captureSessionInFile:temp]; } break; case hangup: [[term pushState] reset]; [modem hangup]; [term popState]; break; case nop: break; case echo: while ([source getline:temp size:sizeof(temp)]) { [term putString:temp]; [term putString:" "]; } [term putString:"\n"]; break; case say: { int firstarg=1; while ([source getline:temp size:sizeof(temp)]) { if (firstarg) firstarg = 0; else [modem writeOut:" "]; [modem writeOut:temp]; } [modem writeOut:"\r"]; } break; case expect: { // can't write this bit just yet } break; default: break; } return self; } - doEscape:(char) func { return [self doFunction:keymap[func] withInput:term]; } - bindChar:(char) ch toFunction:(enum escapeFunction) func { keymap[ch] = func; return self; } - autoDial:(char *)dialString { id s; id sr; int i; char line[200]; enum responses {connect=1,connect1200,connect2400,no_carrier,busy,no_dialtone,user_abort}; enum responses seen; s = [Fdset new]; [s addfd:[modem getfd]]; [s addfd:[term getfd]]; sr = [StringResponder new]; [sr addString:"CONNECT!" returnValue:connect]; [sr addString:"CONNECT 1200!" returnValue:connect1200]; [sr addString:"CONNECT 2400!" returnValue:connect2400]; [sr addString:"NO CARRIER!" returnValue:no_carrier]; [sr addString:"BUSY!" returnValue:busy]; [sr addString:"NO DIALTONE!" returnValue:no_dialtone]; try_again: [modem writeOut:dialString paced:10000]; for (seen=0; !seen && [s waitOnInputFor:60]; ) { if ([s getReadyfd] == [term getfd]) { // check for user abort [term readInto:line]; if (strchr(line,27)) { seen = user_abort; break; } } [modem readInto:line]; [term putString:line]; for (i=0;i<strlen(line);i++) { // convert end of line chars to ! if (line[i]=='\r' || line[i]=='\n') line[i]='!'; } seen = [sr inputString:line]; } if (!seen) [term putString:"modem is not responding as expected\n"]; else { switch (seen) { case connect: [term ringBell]; break; case connect1200: [modem setSpeed:1200]; [term ringBell]; break; case connect2400: [modem setSpeed:2400]; [term ringBell]; break; case no_carrier: [term putString:"modem detected no carrier, trying again...\n"]; goto try_again; break; case busy: [term putString:"busy, trying again...\n"]; sleep(10); goto try_again; break; case no_dialtone: [term putString:"modem couldn't get dialtone; check phone\n"]; break; case user_abort: [term putString:"User aborted dialing\n"]; break; } } [s free]; [sr free]; return self; } @end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.