home *** CD-ROM | disk | FTP | other *** search
- /* xcb+.c -- CIS B+ Protocol module for XC
- This file uses 4-character tabstops
- */
-
- #include <stdio.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <signal.h>
- #include <time.h>
- #include <fcntl.h>
- #include <ctype.h>
- #define NODEBUG 1 /* prevents xc.h from defining DEBUG */
- #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 Send_Ahead_Buffers 5
-
- enum {
- Check_B,
- Check_CRC
- } ;
-
- enum {
- Quote_Default,
- Quote_Not_NULL,
- Quote_Extended,
- Quote_Full,
- Quote_Mask
- } ;
-
- enum {
- Overwrite,
- Resume
- } ;
-
- enum {
- Resume_Allowed,
- Resume_Not_Allowed,
- Resume_Failed,
- Resume_Denied
- } ;
-
- 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;
-
- extern short cr_add;
- extern void cl_line();
- static char S_Buffer[1033], R_Buffer[1033], tdir[32];
- char Name[SM_BUFF];
- static unchar Mask[32];
- static unsigned Checksum;
- static 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;
-
- struct {
- int Seq;
- int PackeT_Size;
- char *packet;
- } Pending[Send_Ahead_Buffers];
-
- extern ushort 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+ logging */
-
- #ifdef CIS_DEBUG
- static FILE *bfp = NIL(FILE);
- static void
- xclog(dir, val)
- char dir;
- int val;
- {
- static int cnt, lastdir;
-
- if (!bfp)
- bfp=fopen("xc.log","w"),
- cnt=0,
- lastdir=dir;
-
- if (++cnt>20||lastdir!=dir)
- fputc('\n',bfp),
- cnt=1;
-
- if (lastdir!=dir)
- fputc('\n',bfp);
-
- 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);
- S0(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)
- 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)
- ttgoto(LI-6,26),
- fputs("estimating",tfp);
- else
- rate=chars/elapsed,
- rem=(fsize-(data+carriage_return-already_have))/rate,
- minutes=rem/60,
- sec=rem%60,
- rate_percent=1000*rate/mrate(NIL(char)),
-
- 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,23),
- fprintf(tfp,"Rate: %d characters per second ", 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)
- 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);
- fputs(Msg,tfp);
-
- time(&start);
- }
-
- static void
- Discard_ACKed_Packets()
- {
- int i, n;
- 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=NIL(char),
- 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=(mrate(NIL(char))) > 1200 ? 1025 : 513; */
- i=mrate(NIL(char));
- PackeT_Size=(i>2400) ? 2049 : (i>1200) ? 1025 : 513;
-
- Quoting=Quote_Mask;
-
- for (i=0;i<Send_Ahead_Buffers;i++)
- Pending[i].packet=NIL(char);
-
- Actual_Check=Check_B;
- Abort_Flag=Sent_ENQ=FALSE;
-
- memset(Mask,0,32);
-
- Mask[ETX]=Mask[ENQ]=Mask[DLE]=Mask[NAK]=Mask[XON]=Mask[XOFF]=MaskLowRange;
-
- total_sent=total_read=data=fsize=Read_Errors=Send_Errors=
- already_have=carriage_return=0;
- fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n",tfp);
- ttgoto(LI-14,25);
- S1("CIS B-Plus Protocol Transfer");
-
- ttgoto(LI-10,0);
- fputs("B+ Bytes Sent B+ Bytes Rcvd",tfp);
- ttgoto(LI-10,40);
- fputs("Data Bytes Carriage Returns",tfp);
- ttgoto(LI-6,10);
- fputs("Time Remaining:",tfp);
- ttgoto(LI-6,48);
- fputs("Elapsed Time:",tfp);
- }
-
- static void
- Xmit_Packet(Size, Seq, Packet)
- int Size, Seq;
- unchar *Packet;
- {
- register I;
-
- init_check();
- Send_Byte(DLE);
- Send_Byte('B');
- Send_Byte(Seq+'0');
- do_checksum(Seq+'0');
-
- for (I=0;I<Size;I++)
- Send_Masked_Byte(Packet[I]),
- do_checksum(Packet[I]);
-
- Send_Byte(ETX);
- do_checksum(ETX);
- if (Actual_Check==Check_B)
- Send_Masked_Byte(Checksum);
- else
- Send_Masked_Byte(Checksum>>8),
- Send_Masked_Byte(Checksum&0xff);
- }
-
- static
- Wait_For_ACK(Have_DLE_B, Acknowledge, Resend)
- 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 (Errors<Max_Errors)
- switch (Action){
- case S_Get_Data:
- if (Read_Masked_Byte()==FAILURE){
- Action=S_Send_NAK;
- Why_NAK("couldn't read next data byte");
- } else if (Not_Masked && Ch==ETX)
- Action=S_Get_check;
- else if (Not_Masked && Ch==ENQ)
- Action=S_SenD_ACK;
- else if (i==PackeT_Size){
- Action=S_Send_NAK;
- Why_NAK("incoming buffer overflow");
- } else
- R_Buffer[i++]=Ch,
- do_checksum(Ch);
- break;
-
- case S_Get_DLE:
- if (Packets_Btwn_ACKs>Window_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)
- 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;i<PendinG_Count;i++)
- n=(Next_Packet+i)%Send_Ahead_Buffers,
- Xmit_Packet(
- Pending[n].PackeT_Size,
- Pending[n].Seq,
- Pending[n].packet);
- else
- return FAILURE;
-
- Action=S_Get_DLE;
- break;
- }
- return FAILURE;
- }
-
- static void
- Send_Failure(Code, Text)
- char Code;
- char *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 void
- Send_Abort()
- {
- fclose(Data_File);
- sprintf(Msg,"Transfer abort requested");
- S0(Msg);
- Send_Failure('A',Msg);
- }
-
- static
- Send_Packet(Size)
- int Size;
- {
- int Next, Next_Seq;
-
- while ((PendinG_Count>Window_Size))
- if (!Wait_For_ACK(FALSE,TRUE,TRUE)){
- 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=strdup(S_Buffer);
- Pending[Next].PackeT_Size=Size;
- Packets_Btwn_ACKs=0;
-
- Xmit_Packet(Size,Next_Seq,S_Buffer);
-
- return SUCCESS;
- }
-
- static ulong
- cnvAtoL(ptr)
- char *ptr;
- {
- ushort sign=FALSE;
- char ch;
- ulong result=0;
-
- ch= *ptr++;
-
- if (ch=='-')
- sign=TRUE,
- ch= *ptr++;
-
- while (ch>='0'&&ch<='9')
- result=result*10+(ch-'0'),
- ch= *ptr++;
-
- return(sign?-result:result);
- }
-
- static
- char *cnvLtoA(ptr, n)
- char *ptr;
- ulong n;
- {
- char tmp1[11], *tmp2=tmp1;
-
- if (!n){
- *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");
- S0(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;
- }
- if (cismode)
- S0(Msg);
- else
- S2(Msg);
-
- for (;;){
- beep();
- key=toupper(fgetc(stdin));
- 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 NIL(FILE);
-
- case 'R':
- if (Condition==Resume_Allowed){
- Result=Resume;
- return fopen(Name,"r+");
- }
- break;
- }
- fputc('\b',tfp);
- }
- }
- }
-
- static
- Read(fp, buf, want)
- FILE *fp;
- char *buf;
- register int 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 int 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
- 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))){
- 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;i<N;i++)
- do_checksum(S_Buffer[i]);
- if (Abort_Flag){
- Send_Abort();
- return FAILURE;
- }
-
- already_have+=N;
- }
- } while (N>0);
-
- ptr= &S_Buffer[0];
-
- *ptr++ ='T';
- *ptr++ ='r';
-
- ptr=cnvLtoA(ptr,already_have);
- *ptr++ =' ';
- ptr=cnvLtoA(ptr,Checksum);
-
- if (!Send_Packet(ptr- &S_Buffer[0])||!Flush_Pending()){
- fclose(Data_File);
- S0("Can't resume transfer");
- return FAILURE;
- }
-
- fseek(Data_File,0L,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");
- S0(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))){
- 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]);
-
- S0(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)
- 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"))){
- sprintf(Msg,"Can't access '%s'",Name);
- S0(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);
- S0(Handle_Send_Failure());
- return FAILURE;
- }
-
- if (Abort_Flag){
- Send_Abort();
- return FAILURE;
- }
-
- stats(N);
- }
- } while (N>0);
-
- if (!N){
- fclose(Data_File);
- S_Buffer[0]='T';
- S_Buffer[1]='C';
-
- if (!Send_Packet(2)){
- S0(Handle_Send_Failure());
- return FAILURE;
- }
-
- return Flush_Pending();
- } else {
- sprintf(Msg,"Disk read error");
- S0(Msg);
- Send_Failure('I',Msg);
- return FAILURE;
- }
- }
-
- #define Plus_PackeT_Size 18
- #define LowRange 7
- #define HiRange 11
-
- #define My_Send_Window_Size 1
- #define My_Recv_Window_Size 1
- #define My_Buffer_Size 8
- #define My_Check_Method Check_CRC
- #define My_Download_Resume 2
- #define My_Upload_Resume 0
- #define My_File_Information 1
-
- static char Quote_Level_Select_Low[]={
- 1, 3, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 0, 0, 3, 0, 3, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
- };
-
-
- static char QuotE_Level_select_Hi[]={
- 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
- 3, 2, 3, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
- };
-
- static char QUote_Level_Mapping[]={
- Quote_Not_NULL,
- Quote_Default,
- Quote_Extended,
- Quote_Full
- };
-
- static
- Plus_Respond()
- {
- int Status, temp_window_size, temp_method, temp_size, MaskByte, Bit, i;
- char Estimated_Quote_Level=0;
-
- S_Buffer[0]='+';
- S_Buffer[1]=My_Send_Window_Size;
- S_Buffer[2]=My_Recv_Window_Size;
-
- S_Buffer[3]=PackeT_Size/128;
-
- S_Buffer[4]=My_Check_Method;
-
- S_Buffer[5]=Quote_Default;
- S_Buffer[6]=FALSE;
-
- S_Buffer[15]=My_Download_Resume;
- S_Buffer[16]=My_Upload_Resume;
- S_Buffer[17]=My_File_Information;
-
- for (i=0;i<8;i++)
- S_Buffer[i+LowRange]=0;
-
- for (MaskByte=0;MaskByte<4;MaskByte++)
- for (Bit=0;Bit<8;Bit++){
- if (Mask[MaskByte*8+Bit]&MaskLowRange)
- S_Buffer[MaskByte+LowRange]|=0x80>>Bit;
-
- if (Mask[MaskByte*8+Bit]&MaskHiRange)
- S_Buffer[MaskByte+HiRange]|=0x80>>Bit;
- }
-
- for (i=R_BUffer_Len;i<Plus_PackeT_Size;i++)
- R_Buffer[i]=0;
-
- if (R_Buffer[3]<S_Buffer[3])
- temp_size=(R_Buffer[3]*128)+1;
- else
- temp_size=(S_Buffer[3]*128)+1;
-
-
- temp_window_size=min(R_Buffer[2],My_Send_Window_Size);
- temp_method=min(R_Buffer[4],My_Check_Method);
- Valid_To_Resume_Download=min(R_Buffer[15],My_Download_Resume);
- ValiD_To_Resume_Upload=min(R_Buffer[16],My_Upload_Resume);
- Send_FIle_Information=min(R_Buffer[17],My_File_Information);
-
- if (R_BUffer_Len>=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
- 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'){
- S0("Invalid transfer direction");
- Send_Failure('N',"Not implemented");
- return FAILURE;
- }
- if (R_Buffer[2]!='A'&&R_Buffer[2]!='B'){
- S0("Invalid transfer type");
- Send_Failure('N',"Not implemented");
- return FAILURE;
- }
- N=min(R_BUffer_Len-3,SM_BUFF-1);
- for (I=0;I<N;I++)
- Name[I]=R_Buffer[I+3];
- Name[I]='\0';
- textmode=(R_Buffer[2]=='A');
-
- if (R_Buffer[1]=='U'){
- Send_ACK();
- return Send_File();
- } else
- return Receive_File();
-
- } else if (R_Buffer[0]=='+'){
- if (Plus_Respond())
- Have_DLE_B=FALSE;
- else {
- S0("Could not negotiate B-Plus parameters");
- return FAILURE;
- }
- } else {
- Send_Unexpected_Packet();
- return FAILURE;
- }
- } else {
- S0("Remote is not responding");
- return FAILURE;
- }
- }
- }
-
- static
- void cisbsigint(junk)
- int junk;
- {
- signal(SIGINT,cisbsigint);
- Abort_Flag=TRUE;
- }
-
- void
- B_Transfer()
- {
- short Status=FALSE;
- void (*oldvec)();
-
- oldvec = signal(SIGINT,cisbsigint);
- cur_off();
- Init();
- purge();
- 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");
- S0(Msg);
- beep();
-
- if (Abort_Flag){
- while (Read_Byte() && Ch==ENQ){
- Seq_Num=0;
- Send_Byte(DLE);
- Send_Byte('+');
- Send_Byte('+');
- Send_ACK();
- }
- }
-
- cur_on();
- signal(SIGINT,oldvec);
- }
-