This is xcb+.c in view mode; [Download] [Up]
/* 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 <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[2064], R_Buffer[2064], 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, carriage_return;
static time_t start;
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, rem;
time_t elapsed, now;
data+=count;
if (!fsize)
data_percent=0;
else
data_percent=100*(data+carriage_return)/fsize;
if (data_percent>100)
data_percent=100;
now=mtime();
elapsed=now-start;
chars=data+carriage_return-already_have-(tdir[0]=='T'?PackeT_Size:0);
if (elapsed<1000 || !chars)
ttgoto(LI-6,26),
fputs("estimating",tfp);
else
rate=(1000*chars)/elapsed,
rem=(fsize-(data+carriage_return-already_have))/rate,
minutes=rem/60,
sec=rem%60,
ttgoto(LI-6,26),
fprintf(tfp,"%8.1d:%2.2d",minutes,sec),
elapsed/=1000,
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);
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);
start=mtime();
}
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;
i=mrate(NIL(char));
PackeT_Size=(i>2400) ? 2048 : (i>1200) ? 1024 : 512;
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");
init_check();
do {
S_Buffer[0]='N';
N=Read(Data_File,&S_Buffer[0],PackeT_Size);
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);
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);
else
temp_size=(S_Buffer[3]*128);
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
RETSIGTYPE cisbsigint(junk)
int junk;
{
signal(SIGINT,cisbsigint);
Abort_Flag=TRUE;
}
void
B_Transfer()
{
short Status=FALSE;
RETSIGTYPE (*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);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.