Newsgroups: alt.sources From: jpr@jpradley.jpr.com (Jean-Pierre Radley) Subject: XC 3.0b 2/5 Communications Program Date: Tue, 09 Jul 1991 01:02:05 GMT Message-ID: <1991Jul09.010205.7844@jpradley.jpr.com> ---cut--- #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # xcb+.c # xcport.c # myman # This archive created: Mon Jul 8 20:37:35 1991 export PATH; PATH=/bin:$PATH echo shar: extracting "'xcb+.c'" '(23173 characters)' if test -f 'xcb+.c' then echo shar: will not over-write existing file "'xcb+.c'" else sed 's/^|//' << \SHAR_EOF > 'xcb+.c' |/* xcb+.c -- CIS B+ Protocol module for XC | This file uses 4-character tabstops | */ | |#ifdef DEBUG |#undef DEBUG |#endif |#include |#include |#include |#include |#include |#include |#include |#include "xc.h" | |#define min(x,y) ((int)(x)<(int)(y)?(x):(y)) |#define max(x,y) ((int)(x)>(int)(y)?(x):(y)) |#define MaskLowRange 0x01 |#define MaskHiRange 0x10 | |#define Check_B 0 |#define Check_CRC 1 |#define Send_Ahead_Buffers 5 | |#define Quote_Default 0 |#define Quote_Not_NULL 1 |#define Quote_Extended 2 |#define Quote_Full 3 |#define Quote_Mask 4 | |#define Overwrite 0 |#define Resume 1 | |#define Resume_Allowed 0 |#define Resume_Not_Allowed 1 |#define Resume_Failed 2 |#define Resume_Denied 3 | |extern short cr_add; |extern void cl_line(); |static char S_Buffer[1033], R_Buffer[1033], tdir[32]; |char Name[SM_BUFF]; |static unsigned char Mask[32]; |static unsigned Checksum; |static int Ch, /* last char read from remote */ | Quoting, /* quoting level requested by the user */ | Window_Size, /* Send size of send ahead window */ | PackeT_Size, /* Maximum block size. */ | R_BUffer_Len, S_Bytes, R_Bytes, Seq_Num, PendinG_Count, | Next_Packet, Packets_Btwn_ACKs, Last_ACK, textmode, Last_Chr, | Send_Errors, Read_Errors; |static short Max_Errors=10, Abort_Flag, Not_Masked, Sent_ENQ, Actual_Check, | Valid_To_Resume_Download, ValiD_To_Resume_Upload, | Send_FIle_Information, Packet_Received, Result; |static FILE *Data_File; |static long already_have, data, total_read, total_sent, | fsize, start, carriage_return; | |typedef enum { | S_Get_DLE, | S_DLE_Seen, | S_DLE_B_Seen, | S_Get_Data, | S_Get_check, | S_Get_CRC, | S_Verify_CRC, | S_VErify_CKS, | S_VerIfy_Packet, | S_Send_NAK, | S_SenD_ACK, | S_SEnd_ENQ, | S_Resend_Packets, |} Sender_Action; | |typedef struct { | int Seq; | int PackeT_Size; | char *packet; |} PEnding_Element; | |PEnding_Element Pending[Send_Ahead_Buffers]; | |extern unsigned short crc_xmodem_tab[256]; | |static void init_check() |{ | Checksum=Actual_Check ? 0xffff : 0; |} | |static void do_checksum(ch) |unsigned ch; |{ | if (Actual_Check==Check_B){ | Checksum<<=1; | if (Checksum>255) | Checksum=(Checksum&0xFF)+1; | Checksum+=ch&0xFF; | if (Checksum>255) | Checksum=(Checksum&0xFF)+1; | } else | Checksum=(crc_xmodem_tab[((Checksum>>8)^ch)&0xff]^(Checksum<<8))&0xffff; |} | |/* #define CIS_DEBUG /* for B+ record; use only on "fast" hardware */ | |#ifdef CIS_DEBUG |static FILE *bfp; |static void xclog(dir, val) |char dir; |int val; |{ | static int cnt, lastdir; | | if (bfp==NULLF) | bfp=fopen("xc.log","w"), | cnt=0, | lastdir=dir; | | if (++cnt>20||lastdir!=dir) | fprintf(bfp,"\n"), | cnt=1; | | if (lastdir!=dir) | fprintf(bfp,"\n"); | | if (val>'~'||val<' ') | fprintf(bfp,"%c%1x%1x ",dir,val/16,val%16); | else | fprintf(bfp,"%c%c ",dir,val); | | lastdir=dir; |} | |static void Why_NAK(reason) |char *reason; |{ | sprintf(Msg,"Sending NAK, %s",reason); | show(0,Msg); |} | |#else |#define xclog(dir,val) |#define Why_NAK(reason) |#endif | |static void stats(count) |int count; |{ | int rate, minutes, sec, data_percent, rate_percent; | long chars, elapsed, now, rem; | | data+=count; | | if (fsize==0) | data_percent=0; | else | data_percent=100*(data+carriage_return)/fsize; | | if (data_percent>100) | data_percent=100; | | time(&now); | | elapsed=now-start; | chars=data+carriage_return-already_have-(tdir[0]=='T'?PackeT_Size-1:0); | if (elapsed<5||chars==0) | ttgoto(LI-6,26), | fprintf(tfp,"estimating"); | else { | rate=chars/elapsed; | rem=(fsize-(data+carriage_return-already_have))/rate; | minutes=rem/60; | sec=rem%60; | rate_percent=100*rate/mrate(NULLS); | | ttgoto(LI-6,26); | fprintf(tfp,"%8.1d:%2.2d",minutes,sec); | | minutes=elapsed/60; | sec=elapsed%60; | ttgoto(LI-6,61); | fprintf(tfp,"%8.1d:%2.2d",minutes,sec); | | ttgoto(LI-4,14); | fprintf(tfp,"Rate is %d chars per second (%d %% of nominal bps) \n", | rate,rate_percent); |/* | ttgoto(LI-4,26); | fprintf(tfp,"Rate is %d chars per second \n", | rate,rate_percent); |*/ | } | | ttgoto(LI-8,0), | fprintf(tfp,"%8.1ld",total_sent), | ttgoto(LI-8,20), | fprintf(tfp,"%8.1ld",total_read), | ttgoto(LI-8,40); | if (data_percent==0) | fprintf(tfp,"%8.1ld",data); | else | fprintf(tfp,"%8.1ld %3.1u %%",data,data_percent); | if (carriage_return) | ttgoto(LI-8,60), | fprintf(tfp,"%+7.1ld",carriage_return); |} | |static void showmode() |{ | int l; | sprintf(Msg,"%s %s (%ld bytes) as %s",tdir,Name,fsize, | textmode?"ASCII":"BINARY"); | | ttgoto(LI-12,0); | cl_line(); | if ((l=strlen(Msg)) < CO) | ttgoto(LI-12,(CO-l)/2 -1); | fprintf(tfp,Msg); | | time(&start); |} | |static void Discard_ACKed_Packets() |{ | int i, n; | unsigned short Packet_Acked=FALSE; | | Last_ACK=Ch; | n=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers; | | for (i=PendinG_Count;i>0;i--){ | n--; | if (n<0) | n+=5; | | if (Pending[n].Seq==Ch-'0') | Packet_Acked=TRUE, | Next_Packet=(n+1)%Send_Ahead_Buffers; | | if (Packet_Acked==TRUE) | free(Pending[n].packet), | Pending[n].packet=NULLS, | PendinG_Count--; | } |} | |static void Send_Byte(ch) |int ch; |{ | sendbyte(ch); | total_sent++; | xclog('>',ch); |} | |static void Send_Masked_Byte(ch) |int ch; |{ | if (ch<0x20){ | if (Quoting==Quote_Full||(Mask[ch]&MaskLowRange)) | Send_Byte(DLE), | ch+='@'; | } else if (ch>=0x80&&ch<0xA0&& | (Quoting==Quote_Full||(Mask[ch-0x80]&MaskHiRange))) | Send_Byte(DLE), | ch=ch+'`'-0x80; | | Send_Byte(ch); |} | |static Read_Byte() |{ | if ((Ch=readbyte(10))== -1) | return FAILURE; | total_read++; | xclog('<',Ch); | return SUCCESS; |} | |static Read_Masked_Byte() |{ | Not_Masked=TRUE; | | if (!Read_Byte()) | return FAILURE; | | if (Ch==DLE){ | if (!Read_Byte()) | return FAILURE; | | Not_Masked=FALSE; | | if (Ch>='`') | Ch+=0x80; | | Ch&=0x9F; | } | return SUCCESS; |} | |static void Send_ACK() |{ | Send_Byte(DLE); | Send_Byte(Seq_Num+'0'); |} | |static void Init() |{ | int i; | | R_BUffer_Len=Window_Size=PendinG_Count=Next_Packet= | R_Bytes=S_Bytes=Seq_Num=Packets_Btwn_ACKs=Last_ACK=0; | | PackeT_Size=(10*mrate(NULLS)) > 1200 ? 1025 : 513; | | Quoting=Quote_Mask; | | for (i=0;i>8), | Send_Masked_Byte(Checksum&0xff); |} | |static void Send_Failure(Code,Text) |char Code, *Text; |{ | int Len, Seq; | | S_Buffer[0]='F'; | S_Buffer[1]=Code; | Len=2; | while (*Text) | S_Buffer[Len++]= *Text++; | | Seq=(Seq_Num+1)%10; | | while (PendinG_Count&&Wait_For_ACK(FALSE,FALSE,FALSE)) | ; | | Xmit_Packet(Len,Seq,S_Buffer); | | do | Wait_For_ACK(FALSE,FALSE,FALSE); | while (Packet_Received); |} | |static Flush_Pending() |{ | while (PendinG_Count) | if (!Wait_For_ACK(FALSE,TRUE,TRUE)) | return FAILURE; | | return SUCCESS; |} | |static Wait_For_ACK(Have_DLE_B,Acknowledge,Resend) |unsigned short Have_DLE_B, Acknowledge, Resend; |{ | Sender_Action Action; | | int i=0, n, RCV_Num, Errors=0; | | R_BUffer_Len=0; | Packet_Received=FALSE; | | if (Have_DLE_B) | Action=S_DLE_B_Seen; | else | Action=S_Get_DLE; | | while (ErrorsWindow_Size+2&&PendinG_Count){ | Packets_Btwn_ACKs=0; | Action=S_SEnd_ENQ; | continue; | } | if (!Read_Byte()) | Action=S_SEnd_ENQ; | else if (Ch==DLE) | Action=S_DLE_Seen; | else if (Ch==NAK) | Action=S_SEnd_ENQ; | else if (Ch==ENQ) | Action=S_SenD_ACK; | else if (Ch==ETX){ | Action=S_Send_NAK; | Why_NAK("awaiting DLE, got ETX"); | } | break; | | case S_DLE_Seen: | if (!Read_Byte()) | Action=S_SEnd_ENQ; | else if (Ch>='0'&&Ch<='9') | if (Sent_ENQ&&Ch==Last_ACK){ | Sent_ENQ=FALSE; | | if (!PendinG_Count) | return SUCCESS; | else | Action=S_Resend_Packets; | } else { | Discard_ACKed_Packets(); | if (Sent_ENQ) | Action=S_Get_DLE; | else | return SUCCESS; | } | else if (Ch==';') | Action=S_Get_DLE; | else if (Ch=='B') | Action=S_DLE_B_Seen; | else if (Ch==ENQ) | Action=S_SenD_ACK; | else | Action=S_Get_DLE; | break; | | case S_DLE_B_Seen: | if (!Read_Byte()){ | Action=S_Send_NAK; | Why_NAK("no data byte after DLE-B"); | } else if (Ch==ENQ) | Action=S_SenD_ACK; | else | init_check(), | RCV_Num=Ch-'0', | do_checksum(Ch), | i=0, | Action=S_Get_Data; | break; | | case S_Get_check: | do_checksum(ETX); | | if (Read_Masked_Byte()==FAILURE){ | Action=S_Send_NAK; | Why_NAK("no incoming checksum"); | } else if (Not_Masked&&Ch==ENQ) | Action=S_SenD_ACK; | else if (Actual_Check==Check_CRC) | Action=S_Get_CRC; | else | Action=S_VErify_CKS; | break; | | case S_Get_CRC: | do_checksum(Ch); | | if (Read_Masked_Byte()==FAILURE){ | Action=S_Send_NAK; | Why_NAK("no incoming CRC value"); | } else if (Not_Masked&&Ch==ENQ) | Action=S_SenD_ACK; | else | Action=S_Verify_CRC; | break; | | case S_Verify_CRC: | do_checksum(Ch); | | if (Checksum==0) | Action=S_VerIfy_Packet; | else { | Action=S_Send_NAK; | Why_NAK("CRC error"); | } | break; | | case S_VErify_CKS: | if (Checksum==Ch) | Action=S_VerIfy_Packet; | else { | Action=S_Send_NAK; | Why_NAK("Checksum error"); | } | break; | | case S_VerIfy_Packet: | if (RCV_Num==((Seq_Num+1)%10)||R_Buffer[0]=='F'){ | Packets_Btwn_ACKs++; | Seq_Num=RCV_Num; | if (Acknowledge) | Send_ACK(); | R_BUffer_Len=i; | Packet_Received=TRUE; | return FAILURE; | } else if (RCV_Num==Seq_Num) | Action=S_SenD_ACK; | else { | Action=S_Send_NAK; | Why_NAK("packet out of sequence"); | } | break; | | case S_Send_NAK: | ttgoto(LI-2,20); | sprintf(Msg,"Read Errors: %2.1d",++Read_Errors); | S; | Errors++; | Send_Byte(NAK); | Action=S_Get_DLE; | break; | | case S_SenD_ACK: | Send_ACK(); | Action=S_Get_DLE; | break; | | case S_SEnd_ENQ: | ttgoto(LI-2,40); | sprintf(Msg,"Send Errors: %2.1d",++Send_Errors); | S; | Errors++; | Sent_ENQ=TRUE; | Send_Byte(ENQ); | Send_Byte(ENQ); | Action=S_Get_DLE; | break; | | case S_Resend_Packets: | if (Resend){ | for (i=0;iWindow_Size)) | if (!Wait_For_ACK(FALSE,TRUE,TRUE)){ | Send_Abort(); | return FAILURE; | } | | if ((ptr=(char *)malloc(Size))==NULLS){ | Send_Abort(); | return FAILURE; | } | | Next=(Next_Packet+PendinG_Count)%Send_Ahead_Buffers; | PendinG_Count++; | | Next_Seq=Seq_Num=(Seq_Num+1)%10; | Pending[Next].Seq=Next_Seq; | Pending[Next].packet=ptr; | Pending[Next].PackeT_Size=Size; | Packets_Btwn_ACKs=0; | | Xmit_Packet(Size,Next_Seq,S_Buffer); | | for (i=0;i='0'&&ch<='9') | result=result*10+(ch-'0'), | ch= *ptr++; | | return(sign?-result:result); |} | |static char *cnvLtoA(ptr,n) |char *ptr; |unsigned long n; |{ | char tmp1[11], *tmp2=tmp1; | | if (n==0){ | *ptr++ ='0'; | return ptr; | } | | *tmp2++ =0; | do { | *tmp2++ =((char)(n%10))+'0'; | n/=10; | } while (n>0); | | tmp2--; | while (*tmp2) | *ptr++ = *tmp2--; | | return ptr; |} | |static void Send_Unexpected_Packet() |{ | sprintf(Msg,"Unexpected packet type"); | show(0,Msg); | Send_Failure('N',Msg); |} | |FILE *QueryCreate(Offer_Resume) |short Offer_Resume; |{ | int key; | short Condition; | FILE *fileptr; | | Condition = isregfile(Name) ? Offer_Resume : Resume_Denied; | | if (access(Name,0)&&(fileptr=fopen(Name,"w"))){ | Result=Overwrite; | return fileptr; | } else if (access(Name,2)) | Condition = Resume_Denied; | | switch(Condition){ | case Resume_Allowed: | sprintf(Msg,"'%s' exists; Overwrite, Resume, reName, or Abort?",Name); | break; | | case Resume_Not_Allowed: | sprintf(Msg,"'%s' exists; Overwrite, reName, or Abort?",Name); | break; | | case Resume_Failed: | sprintf(Msg,"'%s' CRC error; Overwrite, reName or Abort?",Name); | break; | | case Resume_Denied: | sprintf(Msg,"Permission denied for '%s'; reName, or Abort?",Name); | break; | } | show(0,Msg); | | for (;;){ | beep(); | key=toupper(dgetch()); | if (isupper(key)){ | fputc(key,tfp); | | switch(key){ | case 'O': | if (Condition!=Resume_Denied){ | Result=Overwrite; | return fopen(Name,"w"); | } | break; | | case 'N': | fputc('\r',tfp); | cl_line(); | show(-1,"Enter New Name:"); | getline(); | getword(); | strcpy(Name,word); | return QueryCreate(Offer_Resume); | | case 'A': | return NULLF; | | case 'R': | if (Condition==Resume_Allowed){ | Result=Resume; | return fopen(Name,"r+"); | } | break; | } | fputc('\b',tfp); | } | } |} | |static Receive_File() |{ | char *ptr; | int N, i; | short Request_Resume; | | Result=Overwrite; | if (Valid_To_Resume_Download==2) | Request_Resume=Resume_Allowed; | else | Request_Resume=Resume_Not_Allowed; | | if ((Data_File=QueryCreate(Request_Resume))==NULLF){ | Send_Abort(); | return FAILURE; | } | | chown(Name,getuid(),getgid()); | | if (Result==Resume){ | strcpy(tdir,"Attempting receive resume of"); | showmode(); | | init_check(); | | do { | S_Buffer[0]='N'; | N=Read(Data_File,&S_Buffer[0],PackeT_Size-1); | | if (N>0){ | for (i=0;i0); | | ptr= &S_Buffer[0]; | | *ptr++ ='T'; | *ptr++ ='r'; | | ptr=cnvLtoA(ptr,(unsigned long)already_have); | *ptr++ =' '; | ptr=cnvLtoA(ptr,(unsigned long)Checksum); | | if (!Send_Packet(ptr- &S_Buffer[0])||!Flush_Pending()){ | fclose(Data_File); | show(0,"Can't resume transfer"); | return FAILURE; | } | | fseek(Data_File,(long)0,2); | | strcpy(tdir,"Resuming receive of"); | data=already_have-carriage_return; | carriage_return= -carriage_return; | showmode(); | } else | Send_ACK(), | strcpy(tdir,"Receiving"), | already_have=0; | | for (;;){ | if (Abort_Flag){ | Send_Abort(); | return FAILURE; | } | | Wait_For_ACK(FALSE,TRUE,TRUE); | | if (Packet_Received) | switch(R_Buffer[0]){ | case 'N': | if ((N=Write(Data_File,&R_Buffer[1],R_BUffer_Len-1))== -1){ | sprintf(Msg,"Disk write error"); | show(0,Msg); | Send_Failure('I',Msg); | fclose(Data_File); | return FAILURE; | } | | stats(N); | break; | | case 'T': | switch(R_Buffer[1]){ | case 'I': | fsize=cnvAtoL(&R_Buffer[4]); | showmode(); | break; | | case 'C': | fclose(Data_File); | return SUCCESS; | | case 'f': | fclose(Data_File); | | if ((Data_File=QueryCreate(Resume_Failed))==NULLF){ | Send_Abort(); | return FAILURE; | } | | chown(Name,getuid(),getgid()); | strcpy(tdir,"Receiving"); | data=already_have=carriage_return=0; | showmode(); | break; | | default: | Send_Unexpected_Packet(); | fclose(Data_File); | return FAILURE; | } | break; | | case 'F': | fclose(Data_File); | R_Buffer[R_BUffer_Len]=0; | | if (Result==Resume) | sprintf(Msg,"Can't resume transfer: %s",&R_Buffer[3]); | else | sprintf(Msg,"B protocol Failure: %s",&R_Buffer[3]); | | show(0,Msg); | return FAILURE; | | default: | Send_Unexpected_Packet(); | fclose(Data_File); | return FAILURE; | } | else { | fclose(Data_File); | return FAILURE; | } | } |} | |static char *Handle_Send_Failure() |{ | if (R_BUffer_Len==0) | return("Remote is not responding"); | else { | if (R_Buffer[0]=='F'){ | if (R_BUffer_Len>=2){ | R_Buffer[min(81,R_BUffer_Len)]='\0'; | return(&R_Buffer[1]); | } else | return("No reason given by remote"); | } else { | Send_Failure('E',"Unexpected packet type"); | return("Unexpected packet type"); | } | } |} | |static Send_File() |{ | int N; | struct stat statbuf; | | if ((Data_File=fopen(Name,"r"))==NULLF){ | sprintf(Msg,"Can't access '%s'",Name); | show(0,Msg); | Send_Failure('M',Msg); | return FAILURE; | } | | fstat(fileno(Data_File),&statbuf); | fsize=statbuf.st_size; | | strcpy(tdir,"Transmitting"); | showmode(); | | do { | S_Buffer[0]='N'; | N=Read(Data_File,&S_Buffer[1],PackeT_Size-1); | | if (N>0){ | if (!Send_Packet(N+1)){ | fclose(Data_File); | show(0,Handle_Send_Failure()); | return FAILURE; | } | | if (Abort_Flag){ | Send_Abort(); | return FAILURE; | } | | stats(N); | } | } while (N>0); | | if (N==0){ | fclose(Data_File); | S_Buffer[0]='T'; | S_Buffer[1]='C'; | | if (!Send_Packet(2)){ | show(0,Handle_Send_Failure()); | return FAILURE; | } | | return Flush_Pending(); | } else { | sprintf(Msg,"Disk read error"); | show(0,Msg); | Send_Failure('I',Msg); | return FAILURE; | } |} | |static Do_Transfer() |{ | int I, N; | short Have_DLE_B=TRUE; | | for (;;){ | Wait_For_ACK(Have_DLE_B,FALSE,TRUE); | if (Packet_Received){ | if (R_Buffer[0]=='T'){ | if (R_Buffer[1]!='D'&&R_Buffer[1]!='U'){ | show(0,"Invalid transfer direction"); | Send_Failure('N',"Not implemented"); | return FAILURE; | } | if (R_Buffer[2]!='A'&&R_Buffer[2]!='B'){ | show(0,"Invalid transfer type"); | Send_Failure('N',"Not implemented"); | return FAILURE; | } | N=min(R_BUffer_Len-3,SM_BUFF-1); | for (I=0;I>Bit; | | if (Mask[MaskByte*8+Bit]&MaskHiRange) | S_Buffer[MaskByte+HiRange]|=0x80>>Bit; | } | | for (i=R_BUffer_Len;i=Plus_PackeT_Size) | for (MaskByte=0;MaskByte<4;MaskByte++) | for (Bit=0;Bit<8;Bit++) { | if (R_Buffer[LowRange+MaskByte]&(0x80>>Bit)) | Mask[MaskByte*8+Bit]|=MaskLowRange; | | if (R_Buffer[HiRange+MaskByte]&(0x80>>Bit)) | Mask[MaskByte*8+Bit]|=MaskHiRange; | } | else { | for (i=0;i<32&&Estimated_Quote_Level<3;i++){ | if (Mask[i]&MaskLowRange) | Estimated_Quote_Level= | max(Quote_Level_Select_Low[i],Estimated_Quote_Level); | | if (Mask[i]&MaskHiRange) | Estimated_Quote_Level= | max(QuotE_Level_select_Hi[i],Estimated_Quote_Level); | } | } | | Quoting=Quote_Full; | S_Buffer[5]=QUote_Level_Mapping[Estimated_Quote_Level]; | | if (Status=Send_Packet(Plus_PackeT_Size)) | if (Status=Flush_Pending()){ | Actual_Check=temp_method; | PackeT_Size=temp_size; | Window_Size=temp_window_size; | } | Quoting=Quote_Mask; | | return Status; |} | |static Read(fp,buf,want) |FILE *fp; |char *buf; |register want; |{ | register c; | int read=0; | | while (want--) | switch(c=getc(fp)){ | case EOF: | return read; | | case '\n': | if (cr_add&&textmode&&Last_Chr!='\r') | ungetc(c,fp), | carriage_return++, | c='\r'; | | default: | Last_Chr= *buf++ =c; | read++; | } | | return read; |} | |static Write(fp,buf,want) |FILE *fp; |char *buf; |register want; |{ | int written=0; | | for (;want-->0;buf++){ | if (textmode){ | if (*buf=='\r'){ | Last_Chr= *buf; | continue; | } | if (Last_Chr=='\r') | if (*buf=='\n') | carriage_return--; | else | if (fputc('\r',fp)== -1) | return -1; | else | written++; | | Last_Chr= *buf; | } | | if (fputc(*buf,fp)== -1) | return -1; | else | written++; | } | | return written; |} | |static void cisbsigint() |{ | signal(SIGINT,cisbsigint); | Abort_Flag=TRUE; |} | |void B_Transfer() |{ | short Status=FALSE; | cur_off(); | xc_setflow(FALSE); | intdel(TRUE); | signal(SIGINT,cisbsigint); | Init(); | Send_Byte(DLE); | Send_Byte('+'); | Send_Byte('+'); | Send_ACK(); | | Read_Byte(); | switch(Ch){ | case DLE: | Read_Byte(); | if (Ch=='B') | Status=Do_Transfer(); | break; | | default: | fputc(Ch,tfp); | break; | } | | sprintf(Msg,"File Transfer %s",Status?"Succeeded":"Failed"); | show(0,Msg); | beep(); | | if (Abort_Flag){ | while (Read_Byte() && Ch==ENQ){ | Seq_Num=0; | Send_Byte(DLE); | Send_Byte('+'); | Send_Byte('+'); | Send_ACK(); | } | } | | intdel(FALSE); | xc_setflow(flowflag); | cur_on(); | signal(SIGINT,SIG_IGN); |} SHAR_EOF if test 23173 -ne "`wc -c < 'xcb+.c'`" then echo shar: error transmitting "'xcb+.c'" '(should have been 23173 characters)' fi fi # end of overwriting check echo shar: extracting "'xcport.c'" '(10489 characters)' if test -f 'xcport.c' then echo shar: will not over-write existing file "'xcport.c'" else sed 's/^|//' << \SHAR_EOF > 'xcport.c' |/* xcport.c -- modem interface routines for XC | This file uses 4-character tabstops |*/ | |#include |#include |#include |#include |#include |#include |#include "xc.h" | |#ifdef T6000 |#include |extern int errno; |#endif | |# define LOCKDIR "/usr/spool/uucp" /* system-dependent */ | |#ifdef DIDO |# define DIDOPORT | |# if DIDO == 22 /* SCO Xenix 2.2 uses ungetty */ |# define UNGETTY "/usr/lib/uucp/ungetty" |# define UG_NOTENAB 0 |# define UG_ENAB 1 |# define UG_FAIL 2 |# define SIZEOFLOCKFILE sizeof(short) | static int code, retcode, errflag; |# endif /*DIDO==22*/ | |# if DIDO == 23 /* SCO Xenix 2.3, SCO Unix, other HDB sites */ |# include |# ifndef ASCII_PID |# define ASCII_PID |# define PIDSIZE 10 |# endif | static int gettypid = -1; |# endif /*DIDO==23*/ |#endif /*DIDO*/ | |#ifndef SIZEOFLOCKFILE |#define SIZEOFLOCKFILE sizeof(int) |#endif | |int bitmask = 0xFF, /* modem port i/o data mask */ | cbaud = B2400; /* default bps */ |short flowflag; /* modem port i/o data mask */ |static int mfd = -1, /* modem port file descriptor */ | pid; |static struct termio pmode; /* modem device control string */ |static char port[SM_BUFF], /* modem port device file string */ | lckname[SM_BUFF]; /* lockfile string */ | |void xc_setflow(flow) |short flow; |{ | if (flow) | pmode.c_iflag |= IXON | IXOFF, | pmode.c_iflag &= ~IXANY; | else | pmode.c_iflag &= ~(IXON | IXOFF | IXANY); | | ioctl(mfd, TCSETA, &pmode); |} | |char *mport(s) /* get/set port string */ |char *s; |{ | if (s != NULLS && mfd == -1) | if (strncmp("/dev/", s, 5)) { | strcpy(port, "/dev/"); | strcat(port, s); | } else | strcpy(port, s); | | return(port); |} | |/* Get/set the bps of the modem port. If the port hasn't been opened yet, | just store in pmode for mopen() to use when it opens the port. |*/ |mrate(s) |char *s; |{ | if (s != NULLS) { | switch (atoi(s)) { | case 300: | cbaud = B300; | break; | case 1200: | cbaud = B1200; | break; | case 2400: | cbaud = B2400; | break; | case 9600: | cbaud = B9600; | break; |#ifdef B19200 | case 19200: | cbaud = B19200; | break; |#endif |#ifdef B38400 | case 38400: | cbaud = B38400; | break; |#endif | default: | return(-1); | } | pmode.c_cflag &= ~CBAUD; | pmode.c_cflag |= cbaud; | | ioctl(mfd, TCSETA, &pmode); | } | | switch (pmode.c_cflag & CBAUD) { | case B300: | return(30); | case B1200: | return(120); | case B2400: | return(240); | case B9600: | return(960); |#ifdef B19200 | case B19200: | return(1920); |#endif |#ifdef B38400 | case B38400: | return(3840); |#endif | } | show(1,"Impossible error in bps"); | return(0); |} | |/* The following routine is used to hang up the modem. This is accomplished | by setting bps to 0. According to my documentation on termio, setting bps | to zero will result in DTR not being asserted. This hangs up some (most?) | modems. If not, the second part of the routine sends the Hayes modem | "escape" and then a hangup command. |*/ |hangup() |{ | show(1,"<< HANGUP >>"); | |#if DTR_DROPS_CARRIER | pmode.c_cflag &= ~CBAUD; | pmode.c_cflag |= B0; /* set cbaud 0 (drop DTR) */ | ioctl(mfd, TCSETA, &pmode); | | sleep(1); /* wait a second */ | | pmode.c_cflag &= ~CBAUD; /* reset bps */ | pmode.c_cflag |= cbaud; | ioctl(mfd, TCSETA, &pmode); |#else /* use Hayes command */ | sleep(2); /* Allow for "escape guard time" */ | send_slowly(ATTEN); /* Send modem escape command */ | sleep(3); /* More "escape guard time" */ | send_slowly(HANGUP); /* Send hangup command */ |#endif |} | |#ifdef DIDOPORT |/* suspend() sends signal to a running getty | sets: gettypid, process number of running getty, if SCO 2.3 | retcode, exit value of 'ungetty', if SCO 2.2 | restart(): restarts getty if it had been running before |*/ |#if DIDO == 23 |static void suspend() |{ | struct utmp *t, *getutent(); | char buff[12]; | void endutent(); | | strcpy(buff, strrchr(port, '/') +1); | while ((t = getutent()) != (struct utmp *)0) { | if (t->ut_type == LOGIN_PROCESS && (!strcmp(buff, t->ut_line))) { | gettypid = t->ut_pid; /* get getty PID */ | if (kill(gettypid, SIGUSR1) == -1 && errno != EPERM) | show(1,"Can't signal getty"); | } | } | endutent(); |} |static void restart() |{ | if (gettypid != -1) | kill(gettypid, SIGUSR2); |} |#endif /*DIDO==23*/ |#if DIDO == 22 |static void suspend() |{ | code=errflag=pid=retcode=0; | if ((pid = fork()) == 0) { | execl(UNGETTY, "ungetty", port, NULLS); | show(1,"ungetty exec error"); | exit(8); | } | while (((code = wait(&errflag)) != pid) && code != -1); | switch ((errflag>>8) & 0xff) { | case UG_NOTENAB: /* line acquired: not enabled */ | retcode = UG_NOTENAB; | break; | case UG_ENAB: /* line acquired: need ungetty -r when done */ | retcode = UG_ENAB; | break; | case UG_FAIL: /* could not acquire line */ | case 255: | exit(8); | } |} |static void restart() |{ | code=errflag=pid=0; | if(retcode == UG_ENAB) { | if ((pid = fork()) == 0) { | execl(UNGETTY, "ungetty", "-r", port, NULLS); | exit(8); | } | while (((code = wait(&errflag)) != pid) && code != -1) | ; | } |} |#endif /*DIDO=22*/ |#endif /*DIDOPORT*/ | |/* Opens the modem port and configures it. If the port string is | already defined it will use that as the modem port; otherwise it | gets the environment variable MODEM. Returns SUCCESS or FAILURE. |*/ |mopen() |{ | int c; | char *p; | | if (port[0] == '\0') { | if ((p = getenv("MODEM")) == NULLS) { | show(1, | "Exiting: no modem port specified or present in environment"); | exit(3); | } | mport(p); | } | if (!lock_tty()) | exit(4); | |#ifdef DIDOPORT | p = port +strlen(port) -1; | *p = toupper(*p); | suspend(); |#endif | | if ((mfd = open(port, O_RDWR | O_NDELAY)) < 0) { | sprintf(Msg,"Can't open modem port %s",port); | S; | exit(5); | } | | ioctl(mfd, TCGETA, &pmode); | | pmode.c_cflag &= ~(CBAUD | HUPCL); | pmode.c_cflag |= CLOCAL | cbaud; |#if DIDO == 23 | pmode.c_cflag |= CTSFLOW | RTSFLOW ; |#endif | pmode.c_iflag = IGNBRK; | pmode.c_oflag = pmode.c_lflag = 0; | pmode.c_cc[VMIN] = 1; /* This many chars satisfies reads */ | pmode.c_cc[VTIME] = 0; /* or in this many tenths of seconds */ | | xc_setflow(flowflag); | | c = mfd; | if ((mfd = open(port, O_RDWR)) < 0) { /* Reopen line with CLOCAL */ | sprintf(Msg,"Can't re-open modem port %s",port); | S; | return FAILURE; | } | close(c); | | return SUCCESS; |} | |/* Attach standard input and output to the modem port. This only gets called | after a fork by the child process, which then exec's a program that uses | standard i/o for some data transfer protocol. (To put this here is actually | a kludge, but I wanted to keep the modem-specific stuff in a black box.) |*/ |void mattach() |{ | dup2(mfd, 0); /* close local stdin and connect to port */ | dup2(mfd, 1); /* close local stdout and connect to port */ | | close(mfd); /* close the old port descriptor */ |} | |static void alrm() |{ /* do nothing */ |} | |/* Get a byte from the modem port within 'seconds' or return -1. | All data read from the modem are input through this routine. |*/ |readbyte(seconds) |unsigned seconds; |{ | static int count = 0; | static char *p, rxbuf[10240]; | unsigned alarm(); | | if (count > 0) { | count--; | return(*p++ & 0xff); | } | if (seconds) { | signal(SIGALRM, alrm); | alarm(seconds); | } | if ((count = read(mfd, p = rxbuf, 10240)) < 1) | return(-1); | if (seconds) | alarm(0); | | count--; | return(*p++ & 0xff); |} | |/* Read a byte using bitmask */ |read_mbyte(secs) |unsigned secs; |{ | int c; | | return (c = readbyte(secs)) == -1 ? -1 : c & bitmask; |} | |/* Output a byte to the modem port. | All data sent to the modem are output through this routine. |*/ |void sendbyte(ch) |int ch; |{ | char c = ch & 0xff; | | if(write(mfd, &c, 1)<0) | show(1,"sendbyte: write error!"); |} | |/* Send a byte using bitmask */ |void send_mbyte(ch) |int ch; |{ | sendbyte(ch & bitmask); |} | |void send_slowly(s) |char *s; |{ | while (*s) { | send_mbyte(*s++); | msecs(35); | } |} | |/* send a modem break */ |xmitbrk() |{ | show(1,"<< BREAK >>"); | ioctl(mfd, TCSBRK, 0); |} | |/* lock_tty() returns FAILURE if the lock file exists (and XC will not run). | | unlock_tty() deletes the lock file. | | SCOXENIX 2.3 mods: Steve Manes | Check for active LCK file and try to delete it | | SCOXENIX 2.2 mods: Jean-Pierre Radley | As above, using 'ungetty' | | Tandy 6000 mods: Fred Buck |*/ | |static lock_tty() |{ | int lckfd; | char *s, buff[12]; |#ifdef ASCII_PID | static char apid[PIDSIZE+2] = { '\0' }; |#else | pid = -1; |#endif | | strcpy(buff, strrchr(port, '/') +1); | s = buff + strlen(buff) - 1; | |#if DIDO == 22 | *s = toupper(*s); |#endif |#if DIDO == 23 | *s = tolower(*s); |#endif | | sprintf(lckname, "%s/LCK..%s", LOCKDIR, buff); | | if (!checkLCK()) /* check LCK file */ | return FAILURE; /* can't unlock it */ | | if ((lckfd = creat(lckname, 0666)) < 0) { | sprintf(Msg,"Can't create %s", lckname); | S; | return FAILURE; | } | |#ifdef ASCII_PID | sprintf(apid, "%*d\n", PIDSIZE, getpid()); | write(lckfd, apid, PIDSIZE+1); |#else | pid = getpid(); | write(lckfd, (char *)&pid, SIZEOFLOCKFILE); |#endif | | close(lckfd); | return SUCCESS; |} | |void unlock_tty() |{ | static char byettyxx[50], *byeptr; | extern char *ttyname(); | | sprintf(byettyxx,"BYE%s", strrchr(ttyname(mfd),'/')+1); | byeptr = getenv(byettyxx); | if (byeptr != NULLS && *byeptr) { | show(1,"Sending BYE string to modem"); | send_slowly("\r\r"); | send_slowly(byeptr); | send_slowly("\n"); | } | | pmode.c_cflag &= ~CLOCAL; | pmode.c_cflag |= B0 | HUPCL; | ioctl(mfd, TCSETA, &pmode); | close(mfd); | | setuid((int)geteuid()); | setgid((int)getegid()); | unlink(lckname); |#ifdef DIDOPORT | restart(); |#endif | show(1,"Exiting XC"); |} | |/* check to see if lock file exists and is still active. | kill(pid, 0) only works on ATTSV, some BSDs and Xenix | returns: SUCCESS, or | FAILURE if lock file active | added: Steve Manes 7/29/88 |*/ |checkLCK() |{ | int rc, fd; |#ifdef ASCII_PID | char alckpid[PIDSIZE+2]; |#endif |#if DIDO == 22 | short lckpid = -1; |#else | int lckpid = -1; |#endif | | if ((fd = open(lckname, O_RDONLY)) == -1) { | if (errno == ENOENT) | return SUCCESS; /* lock file doesn't exist */ | goto unlock; | } |#ifdef ASCII_PID | rc = read(fd, (char *)alckpid, PIDSIZE+1); | close(fd); | lckpid = atoi(alckpid); | if (rc != 11) { |#else | rc = read(fd, (char *)&lckpid, SIZEOFLOCKFILE); | close(fd); | if (rc != SIZEOFLOCKFILE) { |#endif | show(1,"Lock file has bad format"); | goto unlock; | } | | /* now, send a bogus 'kill' and check the results */ | if (kill(lckpid, 0) == 0 || errno == EPERM) { | sprintf(Msg,"Lock file process %d on %s is still active - try later", | lckpid, port); | S; | return FAILURE; | } | |unlock: | if (unlink(lckname) != 0) { | sprintf(Msg,"Can't unlink %s file", lckname); | S; | return FAILURE; | } | return SUCCESS; |} SHAR_EOF if test 10489 -ne "`wc -c < 'xcport.c'`" then echo shar: error transmitting "'xcport.c'" '(should have been 10489 characters)' fi fi # end of overwriting check echo shar: extracting "'myman'" '(2564 characters)' if test -f 'myman' then echo shar: will not over-write existing file "'myman'" else sed 's/^|//' << \SHAR_EOF > 'myman' |'''\" JPRadley 'myman' macros June 1989 |.dsx1 XENIX |.. |.de}E |.ft1 |.in\\n()Ru+\\n(INu |.ll\\n(LLu |.lt\\n(LLu |.pl\\n()Lu |.. |.deDT |.. |.de}H |.ev1 |' .lt7.5i |.}E |.ie\\*(]L .tl \\*(]H\\*(]D\\*(]W |.el.tl \\*(]H\\*(]D \|\\*(]L\\*(]W |.sp |.ev |.ns |.. |.deTH |.nrIN \\n()Mu |.ds]H \\$1(\\$2) |.ds]D \*(x1 |.ds]L |.if!\\$3 .ds ]L (\^\\$3\^) |.if!\\$4 .ds ]D \\$4 |.}H |.nr)I \\n()Mu |.nr)R 0 |.}E |.na |.hy14 |.. |.deSH |.}X 0 "\\$1" smaller |.nr)E 2 |\&\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 |.. |.deSS |.}X3n "" "" |.nr)E 2 |\&\\$1 \|\\$2 \|\\$3 \|\\$4 \|\\$5 \|\\$6 |.. |.de}X |.}E |.ti\\$1 |.sp |.nr)R 0 |.fi |.it1 }N |.if!\\$3 .SM |.. |.de}2 |.nr)E 0 |.}E |.nr)I \\n()Mu |.ns |.. |.deSM |.if!\\$1 \&\\$1 |.if!\\$2 \&\\$2 |.if!\\$3 \&\\$3 |.if!\\$4 \&\\$4 |.if!\\$5 \&\\$5 |.if!\\$6 \&\\$6 |.if\\$1 .it 1 }N |.. |.deI |.ft2 |.it1 }N |.if!\\$1 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 |.. |.deB |.ft3 |.it1 }N |.if!\\$1 \&\\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 \\$9 |.. |.deRI |.}S1 2 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.deIR |.}S2 1 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.deIB |.}S2 3 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.deRB |.}S1 3 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.deBR |.}S3 1 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.deBI |.}S3 2 \& "\\$1" "\\$2" "\\$3" "\\$4" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.. |.de}S |.ds]F |.if\\$12 .if !\\$5 .ds ]F\^ |.ie!\\$4 .}S \\$2 \\$1 "\\$3\f\\$1\\$4\\*(]F" "\\$5" "\\$6" "\\$7" "\\$8" "\\$9" |.el\\$3 |.ft1 |.. |.dePP |.sp |.}E |.nr)I \\n()Mu |.ns |.. |.deP |.PP |.. |.deLP |.PP |.. |.deHP |.sp |.if!\\$1 .nr )I \\$1n |.ll\\n(LLu |.in\\n()Ru+\\n(INu+\\n()Iu |.ti\\n()Ru+\\n(INu |.ft1 |.. |.deIP |.TP \\$2 |\&\\$1 |.. |.deTP |.if!\\$1 .nr )I \\$1n |.sp |.in\\n()Ru |.ns |.it1 }N |.nr)E 1 |.di]B |.. |.de}1 |.ds]X \&\\*(]B\\ |.rm]B |.nr)E 0 |.if!\\$1 .nr )I \\$1n |.ft1 |.ll\\n(LLu |.in\\n()Ru+\\n(INu+\\n()Iu |.ti\\n(INu |.ie!\\n()Iu+\\n()Ru-\w\\*(]Xu-3p \{\\*(]X |.br\} |.el\\*(]X\h|\\n()Iu+\\n()Ru\c |.ft1 |.. |.de}N |.if\\n()E .br |.di |.if\\n()E0 .ft1 |.if\\n()E1 .}1 |.if\\n()E2 .}2 |.. |.deRS |.nr]\\n+()p \\n()I |.nr)\\n()p \\n()R |.ie!\\$1 .nr )R +\\$1n |.el.nr )R +\\n()I |.nr)I \\n()Mu |.}E |.. |.deRE |.if!\\$1 \{.ie \\$10 .nr )p 1 1 |.el.nr )p \\$1 1 \} |.ds]i \\*(]I\\n()p |.ds]r \\*(]R\\n()p |.nr)I \\*(]i |.nr)R \\*(]r |.if\\n()p .nr )p -1 |.}E |.. |.dePM |.. |.nr )L 1 |.nrLL 7.9i |.dsR (Reg.) |.nr)p 0 1 |.ds]I \\\\n(] |.ds]R \\\\n() |.ds ]W (printed \n(mo/\n(dy/\n(yr) |.pl\n()Lu |.ll\n(LLu |.lt\n(LLu |.ft1 |.nr )M 8n SHAR_EOF echo shar: 87 control characters may be missing from "'myman'" if test 2564 -ne "`wc -c < 'myman'`" then echo shar: error transmitting "'myman'" '(should have been 2564 characters)' fi fi # end of overwriting check # End of shell archive exit 0 Jean-Pierre Radley Unix in NYC jpr@jpr.com jpradley!jpr CIS: 72160,1341