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.