ibm-pc xmodem utility with auto dial/login
pingel at wang7.UUCP
pingel at wang7.UUCP
Wed Jul 9 03:44:12 AEST 1986
Here is a simple xmodem utility. I have used it for a while
with a semi-clone. Hopefully others with not quite compatible clones
will also find this a useful solution. Constructive criticism is
welcome. Flames > /dev/null. :-)
NOT A SHAR FILE!
----------- cut here ------------
/*
This is a simple pc communications utility. Protocols supported are
xmodem and xon/xoff. Other protocols may be added in future.
All commands are available via meta key, ie. <alt>.
Be warned that this code contains hardware dependant routines, see notes.
Terminal emulation is the normal mode. <alt><command-letter> invokes
file transfers etc. See main() for commands.
*/
/* Notes:
a) Timing loops are for 8 Mhz 80186. Decrease by factor of ~3 for
IBM PC. See defines at start of code. If you have system
wait calls throw out the loops.
b) Hardware dependant code exists at end of this file. Convert
com* routines to use interrupt 14 bios calls where available.
c) You will need to change MS-DOS bdos calls to conform to your
libraries.
d) This communications utility was developed for use with Hayes
compatible modems. The modem must be set for V0 and E0 prior
to use. These settings provide for numerical responses and no
echo, respectively.
e) Terminal emulation depends on ansi.sys for handling of tabs
and escape sequences.
f) Putcnb() is simply non-buffered putc. This was used to eliminate
need for newline in display. Replace with putc if possible.
*/
/*
This program is placed in the public domain. Distribution is allowed
provided charges levied do not exceed distribution costs. Modified
versions may be distributed if this notice is included with a list
of modifications.
Copyright 1986 Lee D. R. Pingel
*/
#include <stdio.h>
#include <dos.h>
#include <string.h>
#include <ctype.h>
/* installation dependant parameters */
#define CONTM 10 /* seconds to dial and connect */
#define MCMDTM 3 /* seconds for modem to respond to command */
#define COMINPS 40000L /* loops per second, approximately */
#define LPS 180000L /* simple wait loop interations per second */
#define ERROR -1
#define FALSE 0
#define TRUE ~FALSE
#define DATAMASK 0x7f
#define BLKSIZ 128
#define BPBUF 32
#define BUFFSIZ (BLKSIZ * BPBUF)
#define RETRYMAX 5
#define MAXLOGIN 5
/* special character defines */
#define TIMEOUT -1
#define QUIT 0x1b
#define SOH 1
#define EOT 4
#define ACK 6
#define NAK 0x15
#define XON 0x11
#define XOFF 0x13
#define CAN 0x18
#define ALTP 25
#define ALTR 19
#define ALTS 31
#define ALTQ 16
#define ALTX 45
#define ALTB 48
#define ALTC 46
#define ALTD 32
#define SYSFILE "systems.txt"
/* global parameters */
int connected = FALSE; /* state of phone line */
char buffer[BUFFSIZ]; /* general I/O buffer */
int baud = 1200; /* normal serial settings */
int bits = 7;
int sbits = 1;
char parity = 'E';
char proto = 'x';
/* I/O trace flag */
int trace = FALSE;
/* xmodem receive and send */
recvxmodem(file)
char *file;
{
int blkcur, blk, blkcomp;
int checksum, moddata, firstchar, attempts;
int fd;
unsigned int j, bufptr;
fd = creat(file);
if(fd == ERROR){
return(FALSE);
}
blkcur = 1;
bufptr = 0;
attempts = 0;
serialset(baud, 8, 2, 'N');
comout(NAK);
do{
/* initial synchronization */
do {
firstchar = cominw(5);
}while(firstchar != SOH
&& firstchar != EOT
&& firstchar != CAN
&& firstchar != TIMEOUT);
if (firstchar == TIMEOUT){
comout(NAK);
printmsg("Timeout error.");
attempts++;
continue;
}
if (firstchar == CAN){
comout(ACK);
printmsg("Transfer canceled by host.");
break;
}
if (firstchar == EOT){
printmsg("Transfer complete.");
comout(ACK);
break;
}
blk = cominw(1);
blkcomp = cominw(1);
if(blk == (~blkcomp & 0xff) && blk == ((blkcur - 1) & 0xff)){
comout(ACK);
printmsg("Duplicate block %x.", blkcur);
while(cominw(1) != TIMEOUT);
attempts++;
continue;
}
if(blk != (~blkcomp & 0xff) /* || blk != (blkcur & 0xff) */ ){
/* commented out as some xmodem go 255,1,2 */
comout(NAK);
printmsg("Block number error, wanted %x and got %x.",
blkcur, blk);
while(cominw(1)!= TIMEOUT);
attempts++;
continue;
}
checksum = 0;
for(j = bufptr; j <(bufptr + BLKSIZ); j++){
moddata = cominw(1);
if(moddata == TIMEOUT) break;
buffer[j] = moddata;
checksum = ((checksum + moddata) & 0xff);
}
moddata = cominw(1);
if(checksum != (moddata & 0xff)){
comout(NAK);
printmsg("Checksum error, got %x expected %x.",
checksum, moddata & 0xff);
attempts++;
continue;
}
printmsg("Block %d.",blkcur);
bufptr += BLKSIZ;
blkcur++;
if(bufptr >= BUFSIZ){
bufptr = 0;
if(write(fd, buffer, BUFSIZ)== ERROR){
comout(CAN);
printmsg("Error writing file.");
break;
}
}
comout(ACK);
}while (attempts < RETRYMAX);
if(attempts >= RETRYMAX)
comout(CAN);
serialset(baud, bits, sbits, parity);
comout(ACK);
if(write(fd, buffer, bufptr)== ERROR){
printmsg("Error writing file.");
}
close(fd);
}
sendxmodem(file)
char *file;
{
int fd, blks, attempts, blkcur, checksum;
unsigned j, bufptr;
char sync;
fd = open(file, 2);
if(fd == ERROR){
printmsg("Cannot open %s.", file);
return;
}
blkcur = 1;
serialset(baud, 8, 2, 'N');
for(attempts = 0; attempts < 10;){
sync = cominw(1);
if(sync == NAK)
break;
else if(sync == TIMEOUT)
attempts++;
}
attempts = 0;
while((blks = read(fd,buffer,BUFFSIZ)) > 0 &&
attempts < RETRYMAX){
if(blks == ERROR){
printmsg("Error reading file.");
close(fd);
return;
}
blks = (blks % BLKSIZ) == 0 ? blks/BLKSIZ :(blks/BLKSIZ) + 1;
bufptr = 0;
do{
attempts = 0;
do{
comout(SOH);
comout(blkcur & 0xff);
comout(~blkcur & 0xff);
checksum = 0;
for(j=bufptr;j<(bufptr+BLKSIZ);j++){
comout(buffer[j]);
checksum = (checksum + buffer[j]) & 0xff;
}
comout(checksum);
}while(cominw(1)!= ACK && attempts++ < RETRYMAX);
printmsg("Block %d.",blkcur);
bufptr += BLKSIZ;
blkcur++;
blks--;
}while(blks && attempts < RETRYMAX);
}
if(attempts >= RETRYMAX){
printmsg("No acknowledgment of block, aborting.");
comout(CAN);
}
else{
attempts = 0;
do{
comout(EOT);
}while(cominw(1)!= ACK && attempts++ < RETRYMAX);
if(attempts >= RETRYMAX){
printmsg("No acknowledgement of EOF.");
}
}
serialset(baud, bits, sbits, parity);
close(fd);
return;
}
recvascii(file)
char *file;
{
char kbdata, moddata;
int fd;
char *bp,*limit, tmp[16];
fd = creat(file);
if(fd == ERROR){
printmsg("Cannot create %s.",file);
return;
}
bp = buffer;
limit = bp + BUFFSIZ;
kbdata = '\0';
purgeline();
while( comcts()&&(kbdata != QUIT)){
if(kbdrdy()){
kbdata = kbdin();
if (kbdata != QUIT)
comout(kbdata);
}
if(cominrdy()){
moddata = comin();
putcnb(moddata);
*bp++ = moddata;
if(bp >= limit){
comout(XOFF);
bp = tmp;
while((*bp = cominw(1)) != TIMEOUT){
putcnb(*bp);
bp++;
}
*bp = '\0';
write(fd, buffer, BUFFSIZ);
strcpy(buffer, tmp);
bp = buffer + (bp - tmp);
comout(XON);
}
}
}
*bp = CTRLZ;
write(fd,buffer,bp - buffer);
close(fd);
}
sendascii(file)
char *file;
{
int fd,size;
char moddata;
char *cp,*limit;
fd = open(file, 0);
if(fd == ERROR){
printmsg("Cannot open %s.", file);
return;
}
while((size = read(fd,buffer,BUFFSIZ)) > 0){
for(cp = buffer, limit = buffer + size; cp < limit; cp++){
comout(*cp);
if(comin() == XOFF){
do{
moddata = cominw(10);
}while (moddata != XON && moddata != TIMEOUT);
}
}
}
close(fd);
}
/*
Connect uses a file (systems.txt) with one line per remote system:
<name> <phone-number> [<delimiter><host-prompt><delimter><response>etc.]
asys 555-1212 'login:'mylogin'password:'mypassword'
Note that prompt/response string is optional. Normal use is to login
to the remote system. The as many prompt/response pairs may be used as
needed.
*/
connect(namenum)
char *namenum;
{
char name[32], number[32], logseq[80];
char buffer[80];
char *cp, *prompt;
char delimiter;
int moddata;
int attempts;
FILE *fd;
disconnect();
if(isdigit(namenum[0])){
dial(namenum);
return;
}
if((fd = fopen(SYSFILE,"r")) == NULL){
printmsg("Unable ot open %s.",SYSFILE);
return;
}
do{
name[0] = '\0';
logseq[0] = '\0';
logseq[1] = '\0'; /* prompt starts here */
number[0] = '\0';
if(fgets(buffer,80,fd) == NULL){
fclose(fd);
printmsg("Unable to find %s.",namenum);
return;
}
sscanf(buffer,"%s %s %s\n",name,number,logseq);
}while(strcmp(namenum,name) != 0);
dial(number);
if(!connected){
fclose(fd);
return;
}
attempts = 0;
delimiter = logseq[0];
prompt = logseq + 1;
cp = prompt;
comout('\n');
while(*cp != '\0' && attempts < MAXLOGIN){
cp = prompt;
moddata = 0x20;
while(*cp != '\0' && *cp != delimiter && moddata != TIMEOUT){
moddata = cominw(3);
if (*cp == (moddata & 0xff))
cp++;
else
cp = prompt;
}
if(moddata == TIMEOUT){
comout('\n');
attempts++;
prompt = logseq + 1;
}else if(*cp != '\0'){
cp++;
for(;*cp != delimiter && *cp != '\0';cp++){
comout(*cp);
}
comout('\n');
prompt = cp;
if(*cp == delimiter)
prompt++;
}
}
if(*cp != '\0'){
disconnect();
}
fclose(fd);
}
dial(num)
char *num;
{
long time;
char *cp;
connected = TRUE;
for(cp="AT DT "; *cp != '\0'; cp++){
comout(*cp);
}
for(cp=num; *cp != '\0'; cp++){
comout(*cp);
}
comout('\015');
for(time = COMINPS * CONTM; comin() != '1' && time > 0; time--);
if(!time){
disconnect();
printmsg("Failed dial.");
}
}
disconnect()
{
long time;
char *cp;
if(!connected)
return;
for(time = LPS; time > 0; time--); /* wait 2 seconds */
for(cp = "+++"; *cp != '\0'; cp++){
comout(*cp);
}
for(time = LPS; time > 0; time--);
purgeline();
for(cp = "ATH\015"; *cp != '\0'; cp++){
comout(*cp);
}
for(time = COMINPS * CONTM; comin() != '0' && time > 0; time--);
for(time = LPS; time > 0; time--); /* let the line settle */
connected = FALSE;
}
cmd(c)
char c;
{
char cbuf[16];
switch(c){
case ALTX:
if(trace){
printmsg("trace off");
trace = FALSE;
}else{
printmsg("trace on");
trace = TRUE;
}
break;
case ALTB:
printmsg("baud rate (300,1200,2400,4800,9600):%d ",baud);
scanf("%d",&baud);
printmsg("bits per character:%d ",bits);
scanf("%d",&bits);
printmsg("stop bits:%d ",sbits);
scanf("%d",&sbits);
printmsg("parity (Even|Odd|None):%c ",parity);
scanf("%s",cbuf);
switch (cbuf[0] & 0x5f){
case 'E':
parity = 'E';
break;
case 'O':
parity = 'O';
break;
case 'N':
parity = 'N';
break;
}
serialset(baud,bits,sbits,parity);
break;
case ALTD:
printmsg("disconnect in progress");
disconnect(cbuf);
break;
case ALTC:
printmsg("connect (name|number):");
scanf("%s",cbuf);
connect(cbuf);
break;
case ALTR:
printmsg("File:");
scanf("%s",cbuf);
switch(proto){
case 'a':
recvascii(cbuf);
break;
case 'x':
recvxmodem(cbuf);
break;
}
putcnb("\007");
break;
case ALTS:
printmsg("File:");
scanf("%s",cbuf);
switch(proto){
case 'a':
sendascii(cbuf);
break;
case 'x':
sendxmodem(cbuf);
break;
}
putcnb("\007");
break;
case ALTP:
printmsg("protocol (Ascii|Xmodem):[%c]",proto);
while (!kbdrdy());
switch(kbdin() & 0x5f){
case 'A':
proto = 'a';
break;
case 'X':
proto = 'x';
break;
default:
break;
}
putcnb(proto);
break;
}
}
char cmdmsg[] =
"commands: <Alt><Connect|Disconnect|Send|Recv|Protocol|Baudrate|Quit>";
main()
{
char kbdata, moddata;
long time;
char *cp;
serialset(baud,bits,sbits,parity);
for(time = LPS; time > 0; time--); /* wait 2 seconds */
for(cp = "+++"; *cp != '\0'; cp++){
comout(*cp);
}
for(time = LPS; time > 0; time--); /* wait 2 seconds */
printmsg("%s",cmdmsg);
purgeline(); /* remove echo */
kbdata = 0;
while(1){
if(kbdrdy()){
kbdata = kbdin();
if(kbdata == '\0'){
kbdata = kbdin();
if(kbdata == ALTQ)
break;
else
cmd(kbdata);
}
else{
comout(kbdata);
}
}
if(cominrdy()){
moddata = comin();
putcnb(moddata);
}
}
disconnect();
}
/* MESSY! use ansi.sys where available */
printmsg(fmt,arg1,arg2,arg3)
char *fmt;
int arg1,arg2,arg3;
{
char buf[160];
char *cp;
int n;
if (trace) printf("\n");
putcnb('\015');
for(n = 79; n > 0; n--){
putcnb(' ');
}
putcnb('\015');
sprintf(buf,fmt,arg1,arg2,arg3);
for(cp = buf;*cp!= '\0'; cp++){
putcnb(*cp);
}
}
/* I/O trace display */
/* format of report: >15(nak) <01(soh) <e3 <f0 <61(a) <0a(nl) >06(ack) */
char ascii[] = "\
nul soh stx etx eot enq ack bel \
bs ht nl vt np cr so si \
dle dc1 dc2 dc3 dc4 nak syn etb \
can em sub esc fs gs rs us \
sp ! \" # $ % & ' \
( ) * + , - . / \
0 1 2 3 4 5 6 7 \
8 9 : ; < = > ? \
@ A B C D E F G \
H I J K L M N O \
P Q R S T U V W \
X Y Z [ \\ ] ^ _ \
` a b c d e f g \
h i j k l m n o \
p q r s t u v w \
x y z { | } ~ del ";
iotrace(c,flag)
char c;
{
char *cp, *xcp;
char buffer[16];
sprintf(buffer,"%c%x",flag,(c & 0xff));
cp = buffer + strlen(buffer);
if(c < 0x80 && c > 0){
*cp++ = '(';
for(xcp = &ascii[c << 2]; *xcp != ' '; xcp++){
*cp++ = *xcp;
}
*cp++ = ')';
}
*cp++ = ' ';
*cp++ = '\0';
for(cp = buffer; *cp != '\0'; cp++){
putcnb(*cp);
}
}
kbdrdy()
{
struct reg sreg,dreg;
sreg.r_ax = 0x0b00;
intcall(&sreg,&dreg,0x21);
return(dreg.r_ax & 0xff);
}
char kbdin()
{
struct reg sreg,dreg;
sreg.r_ax = 0x0700;
intcall(&sreg,&dreg, 0x21);
return(dreg.r_ax & 0xff);
}
/*********************************************************/
/* device specific code */
/********************************************************/
#define MR1 0
#define MR2 0
#define SR 2
#define CSR 2
#define CR 4
#define HR 6
#define STRTCTR 0x1c
#define SPB 0x1c
#define STPCTR 0x1e
#define IP 0x1a
#define OPCR 0x1a
#define IPCR 0x8
#define ACR 0x8
#define ISR 0xa
#define IMR 0xa
#define CTU 0xc
#define CTL 0xe
static int duart = 0x80; /* base of duart channel */
/* the following code is written for the 1681 DUART */
serialset(baud,bits,sbits,parity)
int baud,bits,sbits;
char parity;
{
int mr1,mr2,csr;
mr1 = 0x80;
mr2 = 0x30;
switch(baud){
case 300:
csr = 0x44;
break;
case 1200:
csr = 0x66;
break;
case 2400:
csr = 0x88;
break;
case 4800:
csr = 0x99;
break;
case 9600:
csr = 0xbb;
break;
}
switch(bits){
case 7:
mr1 |= 2;
break;
case 8:
mr1 |= 3;
break;
}
switch(sbits){
case 1:
mr2 |= 7;
break;
case 2:
mr2 |= 0xf;
break;
}
switch(parity){
case 'E':
break;
case 'O':
mr1 |= 4;
break;
case 'N':
mr1 |= 0x10;
break;
}
outb(duart + IMR, 0x0);
outb(duart + CR, 0x15);
outb(duart + CSR, csr);
outb(duart + MR1, mr1);
outb(duart + MR2, mr2);
}
purgeline()
{
while(cominw(1) != TIMEOUT);
}
cominw(seconds) /* int to differentiate TIMEOUT */
unsigned seconds;
{
int c;
long idle;
idle = seconds * COMINPS;
while(!cominrdy()&& idle)
--idle;
if(!idle)
return(TIMEOUT);
c = inb(duart + HR);
c &= 0xff; /* ensure 0xff doesn't appear as 0xffff */
if (trace) iotrace(c,'>');
return(c);
}
comin() /* int so that TIMEOUT is different from data */
{
int c;
if(inb(duart+SR) & 1){
c = inb(duart + HR);
c &= 0xff; /* ensure 0xff doesn't appear as 0xffff */
if (trace) iotrace(c,'>');
}
else{
c = '\0';
}
return(c);
}
comout(c)
char c;
{
int time;
if (trace) iotrace(c,'<');
time = COMINPS/10;
while(!comoutrdy() && time--);
outb(duart + HR,c);
}
comoutrdy()
{
return(inb(duart+SR) & 0x4);
}
cominrdy()
{
return(inb(duart+SR) & 1);
}
comcts()
{
return TRUE;
}
---------------------------------------------------------------------------
Lee Pingel decvax!wang!wang7!wangvs!pingel
MS 1479 Strictly my own biases and opinions.
Wang Laboratories Inc.
1 Industrial Ave What if we also had to import food???
Lowell, Ma 01850
More information about the Comp.sources.unix
mailing list