home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Communications / IBTip / Source / Escaper.m < prev    next >
Encoding:
Text File  |  1995-06-12  |  8.0 KB  |  344 lines

  1. #import "Escaper.h"
  2. #import "Term.h"
  3. #import "Modem.h"
  4. #import "Source.h"
  5. #import "StringResponder.h"
  6. #import "Fdset.h"
  7. #import <stdio.h>
  8. #import <ctype.h>
  9. #import <libc.h>
  10.  
  11. #define MAXARGS 10
  12. #define stripNL(temp) if (temp[strlen(temp)-1] == '\n') temp[strlen(temp)-1] = 0;
  13.  
  14. struct scriptCommand {
  15.   char *cmd;
  16.   enum escapeFunction func;
  17. };
  18.  
  19. static struct scriptCommand decode[] =
  20. {
  21.   {"nop",nop},
  22.   {"stop",stop},
  23.   {"protocol", protocol},
  24.   {"parity",parity},
  25.   {"send",sendfile},
  26.   {"receive",receivefile},
  27.   {"capture",capture},
  28.   {"hangup",hangup},
  29.   {"baudrate",baudrate},
  30.   {"echo",echo},
  31.   {"say",say},
  32.   {"expect",expect},
  33.   {"dial",dial},
  34.   {"readscript",readscript}
  35. };
  36.  
  37. #define NUL '\0'
  38. void breakIntoWords(char *line, char *words[])
  39. {
  40.   char *p = line;
  41.   int i;
  42.  
  43.   for(i=0; *p; i++) {
  44.     while( *p && isspace(*p))
  45.       p++;
  46.     if (*p == NUL) break;
  47.     words[i]=p;
  48.     while( *p && !isspace(*p))
  49.       p++;
  50.     if (*p)
  51.       *p++ = NUL;
  52.   }
  53.   words[i]=NULL;
  54. }
  55.  
  56. int member(int ch, char * set)
  57. {
  58.   return(strchr(set,ch) != 0);
  59. }
  60.  
  61. @implementation Escaper
  62.  
  63. + newEscaperWithTerm:(id)t andModem:(id)m
  64. {
  65.   int i;
  66.   self = [super new];
  67.   term = t;
  68.   modem = m;
  69.   for (i=0; i<128; i++) keymap[i]=nop;
  70.   keymap['b']=baudrate;
  71.   keymap['d']=dial;
  72.   keymap[CTRL('d')]=stop;
  73.   keymap['p']=protocol;
  74.   keymap[CTRL('p')]=parity;
  75.   keymap['s']=sendfile;
  76.   keymap['r']=receivefile;
  77.   keymap['c']=capture;
  78.   keymap['h']=hangup;
  79.   keymap['e']=readscript;   // for (e)xecute script file
  80.   return self;
  81. }
  82.  
  83. - readScript:(char *)file
  84. {
  85.   FILE *fin;
  86.   char line[200], *args[MAXARGS];
  87.   int i;
  88.   id source;
  89.  
  90.   fin = fopen(file,"r");
  91.   if (fin==NULL) {
  92.     sprintf(line,"couldn't open script file %s\n",file);
  93.     [term putString:line];
  94.     return nil;
  95.   }
  96.   while (fgets(line,sizeof(line),fin)) {
  97.     breakIntoWords(line,args);
  98.     if (args[0]==NULL || *args[0]=='%') continue;  // % is for comments
  99.     for(i=0; i<sizeof(decode)/sizeof(decode[0]); i++) {
  100.       if (strcmp(args[0],decode[i].cmd) == 0) {    // then we found a command
  101.     source = [Source newStrings:args+1];
  102.     [self doFunction:decode[i].func withInput:source];
  103.       }
  104.     }
  105.   }
  106.   return self;
  107. }  
  108.   
  109.  
  110. - doFunction:(enum escapeFunction) func withInput:(id)source
  111. {
  112.   char temp[200];
  113.   switch (func) {
  114.   case dial: {
  115.     char dialPrefix[]="ATDT", dialPostfix[]="\r"; // constants for now; later local var's of modem
  116.     char pn[200];
  117.  
  118.     [source getline:pn size:sizeof(pn) WithPrompt:"Enter phone number:"];
  119.     sprintf(temp,"%s%s%s\n",dialPrefix, pn, dialPostfix);
  120.     [self autoDial:temp];
  121.     break;
  122.   }
  123.   case baudrate: {
  124.     int bps;
  125.     [source getline:temp size:sizeof(temp) WithPrompt:"Enter new baud rate [300,1200,2400,4800,9600]:"];
  126.     sscanf(temp,"%d",&bps);
  127.     [modem setSpeed:bps];
  128.     sprintf(temp,"Modem speed set to %d\n",[modem getSpeed]);
  129.     [term putString:temp];
  130.     break;
  131.   }
  132.   case readscript:
  133.     [source getline:temp size:sizeof(temp) WithPrompt:"Enter script file:"];
  134.     stripNL(temp);
  135.     [self readScript:temp];
  136.     break;
  137.   case stop:
  138.     [term reset];
  139.     [modem endCapture];
  140.     [term putString:"\nquitting \n"];
  141.     exit(0);
  142.     break;
  143.   case protocol: {
  144.     enum direction dir;
  145.     char p;
  146.     do {
  147.       p = [source getcharWithPrompt:"\nEnter direction [(s)end,(r)eceive]:"];
  148.     } while (!member(p,"sr"));
  149.     dir = (p=='s')?tohost:fromhost;
  150.     sprintf(temp, "\nEnter desired %s protocol [(x)modem,xmodem(1)k,(y)modem,(z)modem]:",
  151.         (dir==tohost)?"send":"receive");
  152.     do {
  153.       p = [source getcharWithPrompt:temp];
  154.     } while (!member(p,"x1yz"));
  155.     [modem setProtocol:p dir:dir];
  156.     sprintf(temp,"\nSend protocol is %c\n",[modem getProtocolDir:tohost]);
  157.     [term putString:temp];
  158.     sprintf(temp,"\nReceive protocol is %c\n",[modem getProtocolDir:fromhost]);
  159.     [term putString:temp];
  160.     break;
  161.   }
  162.   case parity: {
  163.     int par, parity;
  164.     do {
  165.       par = [source getcharWithPrompt:"\nEnter desired parity (even, odd, or none) [e,o,n]:"];
  166.       if (par=='e' || par=='E')
  167.     parity=EVENP;
  168.       else if (par=='o' || par=='O')
  169.     parity=ODDP;
  170.       else if (par=='n' || par=='N')
  171.     parity=NOPARITY;
  172.       else
  173.     parity=ILLEGAL_PARITY;
  174.     } while (parity == ILLEGAL_PARITY);
  175.     [modem setParity:parity];
  176.     sprintf(temp,"\nParity is %c\n",par);
  177.     [term putString:temp];
  178.     break;
  179.   }
  180.   case sendfile:
  181.     {
  182.       char trigger[100];
  183.       struct stat dummy;
  184.       int cc;
  185.  
  186.       do {
  187.     [source getline:temp size:sizeof(temp) WithPrompt:"\nEnter file to send:"];
  188.     stripNL(temp);
  189.     // check for existence of file
  190.     if ((cc = stat(temp, &dummy)) != 0)
  191.       [source putString:"Couldn't open file...try again"];
  192.       } while (temp[0] && cc != 0);  // null filename means abort command
  193.       if (temp[0]) {
  194.     [source getline:trigger size:sizeof(trigger) WithPrompt:"\nEnter command to send to host:"];
  195.     [[term pushState] reset];
  196.     [modem writeOut:trigger];
  197.     [modem sendFile:temp];
  198.     [term popState];
  199.       }
  200.       break;
  201.     }
  202.   case receivefile:
  203.     [[term pushState] reset];
  204.     [modem receive];
  205.     [term popState];
  206.     break;
  207.   case capture:
  208.     if ([modem isCapturing]) {
  209.       [term putString:"Ending capture to file\n"];
  210.       [modem endCapture];
  211.     }
  212.     else {
  213.       [source getline:temp size:sizeof(temp) WithPrompt:"\nEnter file to save to [tip.record]:"];
  214.       stripNL(temp);
  215.       if (*temp == 0)
  216.     strcpy(temp,"tip.record");
  217.       [modem captureSessionInFile:temp];
  218.     }
  219.     break;
  220.   case hangup:
  221.     [[term pushState] reset];
  222.     [modem hangup];
  223.     [term popState];
  224.     break;
  225.   case nop:
  226.     break;
  227.   case echo:
  228.     while ([source getline:temp size:sizeof(temp)]) {
  229.       [term putString:temp];
  230.       [term putString:" "];
  231.     }
  232.     [term putString:"\n"];
  233.     break;
  234.   case say:
  235.     {
  236.       int firstarg=1;
  237.       while ([source getline:temp size:sizeof(temp)]) {
  238.     if (firstarg)
  239.       firstarg = 0;
  240.     else
  241.       [modem writeOut:" "];
  242.     [modem writeOut:temp];
  243.       }
  244.       [modem writeOut:"\r"];
  245.     }
  246.     break;
  247.     case expect:
  248.     {
  249.     // can't write this bit just yet
  250.     }
  251.     break;
  252.   default:
  253.     break;
  254.   }
  255.   return self;
  256. }
  257.  
  258. - doEscape:(char) func
  259. {
  260.   return [self doFunction:keymap[func] withInput:term];
  261. }
  262.  
  263. - bindChar:(char) ch toFunction:(enum escapeFunction) func
  264. {
  265.   keymap[ch] = func;
  266.   return self;
  267. }
  268.  
  269. - autoDial:(char *)dialString
  270. {
  271.   id s;
  272.   id sr;
  273.   int i;
  274.   char line[200];
  275.   enum responses {connect=1,connect1200,connect2400,no_carrier,busy,no_dialtone,user_abort};
  276.   enum responses seen;
  277.  
  278.   s = [Fdset new];
  279.   [s addfd:[modem getfd]];
  280.   [s addfd:[term getfd]];
  281.   sr = [StringResponder new];
  282.   [sr addString:"CONNECT!" returnValue:connect];
  283.   [sr addString:"CONNECT 1200!" returnValue:connect1200];
  284.   [sr addString:"CONNECT 2400!" returnValue:connect2400];
  285.   [sr addString:"NO CARRIER!" returnValue:no_carrier];
  286.   [sr addString:"BUSY!" returnValue:busy];
  287.   [sr addString:"NO DIALTONE!" returnValue:no_dialtone];
  288.   try_again:
  289.   [modem writeOut:dialString paced:10000];
  290.   for (seen=0; !seen && [s waitOnInputFor:60]; ) {
  291.     if ([s getReadyfd] == [term getfd]) { // check for user abort
  292.       [term readInto:line];
  293.       if (strchr(line,27)) {
  294.     seen = user_abort;
  295.     break;
  296.       }
  297.     }
  298.     [modem readInto:line];
  299.     [term putString:line];
  300.     for (i=0;i<strlen(line);i++) {  // convert end of line chars to !
  301.       if (line[i]=='\r' || line[i]=='\n') line[i]='!';
  302.     }
  303.     seen = [sr inputString:line];
  304.   }
  305.   if (!seen)
  306.     [term putString:"modem is not responding as expected\n"];
  307.   else {
  308.     switch (seen) {
  309.     case connect:
  310.       [term ringBell];
  311.       break;
  312.     case connect1200:
  313.       [modem setSpeed:1200];
  314.       [term ringBell];
  315.       break;
  316.     case connect2400:
  317.       [modem setSpeed:2400];
  318.       [term ringBell];
  319.       break;
  320.     case no_carrier:
  321.       [term putString:"modem detected no carrier, trying again...\n"];
  322.       goto try_again;
  323.       break;
  324.     case busy:
  325.       [term putString:"busy, trying again...\n"];
  326.       sleep(10);
  327.       goto try_again;
  328.       break;
  329.     case no_dialtone:
  330.       [term putString:"modem couldn't get dialtone; check phone\n"];
  331.       break;
  332.     case user_abort:
  333.       [term putString:"User aborted dialing\n"];
  334.       break;
  335.     }
  336.   }
  337.   [s free];
  338.   [sr free];
  339.   return self;
  340. }
  341.   
  342.  
  343. @end
  344.