/* kermit.c support routines and main entry point for Uemail file transfer * functions. Kermit send, receive, get, put, finish, and bye supported. * Buffer logging and direct ASCII transfer also available. All actions are * ASCII 7 bit files. Transfers are made into and out of Uemail buffers. */ #include #include #include #include "ed.h" #include "kermit.h" int emacsfile; /* if TRUE then \r become \n on ASCII transfers */ char getfiln[NFILEN]; /* name for remote file get or put */ char deflow[] = "XON/XOFF"; static unsigned char *tsr_ptr = (char *)0x00fffa2d; /* See St internals */ static long *hz_200 = (long *)0x000004ba; int *aaddress(); /* thanks Jwahar R. Bammi for this line A code */ int *aline_addr; /* Ptr to base of Aline variables */ int sav_row, sav_col; int flow = DEFLO; /* default flow control */ int defbaud = 7; int bps = DEFBPS; unsigned long *hpterm; /* HOST */ /* KERMIT CTRL command prompt for action and switch to appropriate state. * Returns TRUE on success. !TRUE on failures. Bound to ^_ and HELP on ST. */ kermit(flg, _n) register int flg, _n; { static char command[9]; /* command */ register char key; register int owf; owf = curwp->w_flag; /* save for redraw */ if ((_n=mlreply("Kermit-ST> ",command,8)) != TRUE) return(_n==FALSE ? FALSE : ABORT); /* Initialize these values */ /* Hope the first packet will get across OK */ eol = CR; /* EOL for outgoing packets */ quotech = '#'; /* Standard control-quote char "#" */ pad = 0; /* No padding */ padchar = '\0'; /* Use null if any padding wanted */ timint = DEFTIME; /* Default timeout */ parity = DEFPAR; /* Default to no parity */ logfile = 0; /* Capture flag */ emacsfile = 0; /* Trans to emacs (no EOF) */ en8quote(FALSE); key = tolower(command[0]); switch (key) { case 'b': /* B = Bye */ if(mlyesno("Logout remote")==TRUE) if(gencmdsw('L')==FALSE) { mlwrite("Remote does not ACK BYE"); (*term.t_beep)(); return(FALSE); } return(TRUE); /* No update */ case 'c': /* C = Connect command */ connect(); break; case 'e': /* E = transmit to GNU_EMACS command */ if(usebuffer(NULL,NULL) != TRUE) return(FALSE); gotobob(NULL, 1); update(); mlwrite("[Transmitting %s to remote EMACS]",curbp->b_bna me); emacsfile = 1; trans(); emacsfile = 0; connect(); break; case 'f': /* F = Finish */ if(gencmdsw('F')==FALSE) { mlwrite("Remote does not ACK FINISH"); (*term.t_beep)(); return(FALSE); } return(TRUE); /* No update */ case 'g': /* G = Get command */ if((_n=mlreply("Remote filename: ",getfiln,NFILEN))!=TRU E) return(_n); if(usebuffer(NULL,NULL) != TRUE) return(FALSE); gotoeob(NULL, 1); update(); if((_n=getsw()) == FALSE) { (*term.t_beep)(); mlreply("Get failed. Type ",command,2); } break; case 'l': /* L = Log session */ if(usebuffer(NULL,NULL) != TRUE) return(FALSE); gotoeob(NULL, 1); logfile = TRUE; connect(); break; case 'r': /* R = Receive command */ if(usebuffer(NULL,NULL) != TRUE) return(FALSE); gotoeob(NULL, 1); update(); if((_n=recsw()) == FALSE) { (*term.t_beep)(); mlreply("Receive failed. Type ",command,2); } break; case 'p': /* P = Put command */ if((_n=mlreply("Remote filename: ",getfiln,NFILEN))!=TRU E) return(_n); case 's': /* S = Send command */ if(usebuffer(NULL,NULL) != TRUE) return(FALSE); if (key == 's') strcpy(getfiln,curbp->b_bname); gotobob(NULL, 1); update(); if((_n=sendsw()) == FALSE) { if (key == 's') mlwrite("Send failed"); else mlwrite("Put failed"); (*term.t_beep)(); } if (key == 's') connect(); break; case 't': /* T = transmit command */ if(usebuffer(NULL,NULL) != TRUE) return(FALSE); gotobob(NULL, 1); update(); mlwrite("[Transmitting: %s]",curbp->b_bname); trans(); connect(); break; default: mlwrite("Connect, Send, Receive, Get, Put, Finish, Bye\ , Log, Transfer"); return(FALSE); } /* Restore controlling tty's modes */ owf |= WFHARD; owf |= WFMODE; curwp->w_flag |= owf; sgarbf = TRUE; /* we know screen is garbage after connect */ update(); return(TRUE); } /* * c o n n e c t * * Establish a virtual terminal connection with the remote host, over an * assigned tty line. */ connect() { register int c; setterm(REMOTE); while (1) { if (Bconstat(2)) if(readcon() == FALSE) break; if (Bconstat(1)) { c=readaux(); ttputc(c); if (logfile) { if (c=='\n') { lnewline(); continue; } if (c=='\r') continue; linsert(1,c); } } } setterm(HOST); return(FALSE); } /* set up terminal's screen and allow it to be saved for later. */ setterm(f) int f; { static char scrbase[0x7d10]; static unsigned char firsttime = TRUE; extern int deskcol; if (hpterm == NULL) hpterm = Physbase(); /* init TERM screen address */ if (f == REMOTE) { Bconout(2,0x1b); /* disable cursor */ Bconout(2,'f'); copy(scrbase,hpterm,0x7d00); if (firsttime) { aline_addr = aaddress(); Bconout(2,0x1b); /* clear screen */ Bconout(2,'E'); showhelp(); sav_row = aline_addr[-13];/* save cursor position */ sav_col = aline_addr[-14]; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[%s active at %dbps]",deflow,bps); firsttime = FALSE; } (*term.t_move)(sav_row,sav_col); Bconout(2,0x1b); /* enable cursor */ Bconout(2,'e'); return(TRUE); } else if (f == HOST) { sav_row = aline_addr[-13]; /* save cursor position */ sav_col = aline_addr[-14]; Bconout(2,0x1b); /* disable cursor */ Bconout(2,'f'); copy(hpterm,scrbase,0x7d00); ttopen(); /* restore uemail screen */ Bconout(2,0x1b); /* enable cursor */ Bconout(2,'e'); return(TRUE); } else if (f == SHOWHELP) { sav_row = aline_addr[-13]; /* save cursor position */ sav_col = aline_addr[-14]; Bconout(2,0x1b); /* disable cursor */ Bconout(2,'f'); copy(hpterm,scrbase,0x7d00); /* save current screen */ showhelp(); /* write help message */ while(ttgetc()) /* wait for */ if (scancode == 0x62) /* HELP key */ break; copy(scrbase,hpterm,0x7d00); /* restore old screen */ (*term.t_move)(sav_row,sav_col); Bconout(2,0x1b); /* enable cursor */ Bconout(2,'e'); return(TRUE); } } /* * return the base address of the line A variables * Bammi @ Case */ int * aaddress() { asm("dc.w $A000");/* Line A trap - 0000 is init line-A */ /* d0 and a0 now contain the address * so we can just return and the result * will be valid */ } /* a mini-mlwrite for the terminal mode */ /* VARARGS */ mtwrite(fmt,arg1,arg2,arg3,arg4) register char *fmt; register long arg1,arg2,arg3,arg4; { static char buf[128]; sprintf(buf,fmt,arg1,arg2,arg3,arg4); ttputc(0x1b);ttputc('j'); /* save cursor */ (*term.t_move)(term.t_nrow,0); ttputc(0x1b);ttputc('l'); /* delete line */ Cconws(buf); ttputc(0x1b);ttputc('k'); /* restore cursor */ return(TRUE); } /* A modicum of help for the RS232 connection module */ int showhelp() { register int i; i = 5; Crawio(0x1b); Crawio('p'); /* rev video on */ (*term.t_move)(i++,17); Cconws(" "); (*term.t_move)(i++,17); Cconws(" ALT-UNDO return to Uemail "); (*term.t_move)(i++,17); Cconws(" ALT-B set the baud rate "); (*term.t_move)(i++,17); Cconws(" ALT-C change color "); (*term.t_move)(i++,17); Cconws(" ALT-E load an alias file "); (*term.t_move)(i++,17); Cconws(" ALT-L load a macro file "); (*term.t_move)(i++,17); Cconws(" ALT-O turn off flow control "); (*term.t_move)(i++,17); Cconws(" ALT-R turn on RTS/CTS "); (*term.t_move)(i++,17); Cconws(" ALT-X turn on XON/XOFF "); (*term.t_move)(i++,17); Cconws(" ALT-T show the current time "); (*term.t_move)(i++,17); Cconws(" ALT-CTRL-B send a break "); (*term.t_move)(i++,17); Cconws(" ALT-CTRL-C run a program "); (*term.t_move)(i++,17); Cconws(" ALT-? this help message "); (*term.t_move)(i++,17); Cconws(" HELP this help message "); (*term.t_move)(i++,17); Cconws(" \r\n"); Crawio(0x1b); Crawio('q'); /* rev video off */ return(TRUE); } /* setbaud for RS232 (default is 1200) */ int setbaud() { register int c; mtwrite("Baud rate [a/b/c/d/e] a = 300, \ b = 1200, c = 2400, d = 9600, e = 19,200"); c = ttgetc(); switch(c) { case 'a': case 'A': defbaud = 9; bps = 300; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); case 'b': case 'B': defbaud = 7; bps = 1200; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); case 'c': case 'C': defbaud = 4; bps = 2400; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); case 'd': case 'D': defbaud = 1; bps = 9600; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); case 'e': case 'E': defbaud = 0; bps = 19200; Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); default: Rsconf(defbaud,flow,-1,-1,-1,-1); mtwrite("[Baud = %dbps]",bps); return(TRUE); } } /* * KERMIT utilities. */ /* generic command for BYE and FINish */ gencmdsw(cmd) char cmd; { int num, len; /* Packet number, length */ packet[0] = cmd; /* Generic command */ spack('G', 0, 1, packet); /* Send Generic command */ switch(rpack(&len,&num,packet)) /* Get packet */ { case 'Y': return(TRUE); case 'E': prerrpkt(packet); return(FALSE); default: return(FALSE); } } /* * b u f i l l * * Get a bufferful of data from the buffer that's being sent. * Only control-quoting and 8-bit quoting is done; * repeat count prefixes are not handled. */ bufill(buffer) char buffer[]; /* Buffer */ { register char t; /* Char read from file */ register char *buffend; /* End of buffer pointer */ register char *buffp; /* Pointer into buffer */ register int unprintable; /* Is a character printable ?*/ short eolflag = FALSE; /* kludge for VAX */ buffend = &buffer[spsiz-9]; /* set up end of buffer pointer */ buffp=buffer; /* and the current position */ while(curwp->w_dotp != curbp->b_linep) { t = lgetc(curwp->w_dotp, curwp->w_doto); if (curwp->w_doto == llength(curwp->w_dotp)) { t = eol; eolflag = TRUE; /* kludge for VAX */ } unprintable = ((t=buffend) /* this is how you avoid pointer */ return((int)buffp-(int)buffer); /* subtraction */ } /* not (int)(buffp-buffer) */ if (buffp == buffer) return(EOF); return((int)buffp-(int)buffer); /* Handle partial buffer */ } /* * b u f e m p * * Put data from an incoming packet into the default buffer. */ bufemp(buffer,len) char buffer[]; /* Buffer */ int len; /* Length */ { register int i; /* Counter */ register char t; /* Character holder */ register int highbit; /* place to hold quoted highbit */ highbit = 0; for (i=0; i= 32000) /* time is up */ return(FALSE); return ((int)Bconin(1)); /* char not masked when read */ } sauxstr(buf,len) char *buf; int len; { for(;len>0;len--) sendaux(*buf++); } sendaux(c) int c; { while(!Bcostat(1)) { if (Bconstat(2)) if (ttgetc()==0x07) return(FALSE); } Bconout(1,c); /* Send character */ } /* * p r e r r p k t * * Print contents of error packet received from remote host. */ prerrpkt(msg) char *msg; { mlwrite("ABORT: %s",msg); return; } en8quote(t) int t; { qflag = t; /* no binary files allowed */ } /* tsr_ptr points to the 8 bit TSR register of the 68901 * From Jwahar R. Bammi * send a break * Modifies Bit 3 in the TSR (reg 23) of the Mfp */ sendbrk() { register long save_ssp; register long time; save_ssp = Super(0L); /* Super Mode */ /* set bit 3 of the TSR */ *tsr_ptr |= (unsigned char)8; /* wait for 250 ms -- you can adjust the duration * 250 ms seems to be almost a universal figure for break * duration. */ time = *hz_200 + 50; while(*hz_200 < time) /* wait */ ; /* reset bit 3 of the tsr */ *tsr_ptr &= (unsigned char)~8; Super(save_ssp); /* Back to user Mode */ } /* * f l u s h i n p u t * * Dump all pending input to clear stacked up NACK's. */ flushinput() { /* TOS Clear AUX receive buffer */ while (Cauxis()) Cauxin(); }