#include "ufk.h" int offset, /* Offset in data buffer to start */ org_size; /* Original packet size */ char size_lowered; /* Flag if packet shortening has been done */ sendfile() { if (numprm <= 1) /* check parameter */ prterr(ER_FSPCREQ); else if (!get_file_spec(TRUE)) /* Get filespec for send */ prterr(ER_NOFILSEL); else { if (!open_port(TRUE,FALSE)) /* Setup communication port */ prterr(ER_POPNERR); else { if (alloc_pkt(SEND)) /* Allocate packet memory */ { sflg++; set_frame(); if (!sendsw()) /* Send the file(s) */ disp(0,18,"Send failed.\n"); /* Report failure */ beep(); while (get_file_spec(FALSE)); /* Flush directory buffer */ } close_port(sflg,FALSE); } } } /* * s e n d s w * * Sendsw is the state table switcher for sending files. It loops until * either it finishes, or an error is encountered. The routines called * by sendsw are responsible for changing the state. * */ sendsw() { char sinit(), sfile(), sattr(), sdata(), seof(), sbreak(); init_xfer(); /* Reset counters */ set_default_comm(); /* Set communication parameters */ state = 'S'; /* Send initiate is start state */ n = 0; /* Initialize message number */ offset = 0; /* Offset in data buffer to start */ size_lowered = FALSE; /* No long packet error received */ numtry = 0; /* Say no tries yet */ if (remote && (sflg != 2)) /* Wait before sending if remote */ kdelay(send_delay); /* and if no server mode request */ purgeline(ttyfd); /* Eat old input */ while(TRUE) /* Do this as long as necessary */ { if (debug) { prtdbgf("Send state: "); if (!screen) fputs("Send state: ",stdout); disp_state(50,13,state); } switch(state) { case 'S': /* Send-init */ state = sinit(); break; case 'F': /* Send-file */ state = sfile(); break; case 'A': /* Send attributes */ state = sattr(); break; case 'D': /* Send-data */ state = sdata(); break; case 'Z': /* Send-End-of-File */ state = seof(); break; case 'B': /* Send-Break */ state = sbreak(); break; case 'C': /* Complete */ fin_xfer(); return (TRUE); case 'Q': default: /* Unknown or abort, fail */ fin_xfer(); return (FALSE); } } } /* * s i n i t * * Send Initiate: send this host's parameters and get other side's back. */ char sinit() { char num; /* Packet number */ int len; /* length */ if (numtry++ >= maxtry) /* If too many tries, give up */ return('Q'); spar(sndpkt,&len); /* Fill up init info packet */ spack('S',n,len,sndpkt,0,1); /* Send an S packet */ switch(rpack(&len,&num,recpkt,1)) /* What was the reply? */ { case 'N': /* NAK, try it again */ return(state); case 'Y': /* ACK */ if (n != num) /* If wrong ACK, stay in S state */ return(state); /* and try again */ rpar(recpkt,len); /* Get other side's init info */ numtry = 0; /* Reset try counter */ n = ( n + 1) % 64; /* Bump packet count */ return('F'); /* OK, switch state to F */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* Abort */ case 'T': /* Timeout */ if (aborted) return('Q'); /* aborted by user */ case FALSE: /* Receive failure, try again */ return(state); default: /* Anything else, just "abort" */ return('Q'); } } /* * s f i l e * * Send File Header. */ char sfile() { char num, /* Packet number */ fnm[15]; int i, len; /* length */ if (numtry++ >= maxtry) /* If too many tries, give up */ return('Q'); aborted = FALSE; if (fp != ERROR) /* If left open, close it */ fclose(fp); fp = fopen(filnam,"r"); /* open the file to be sent */ if (fp == NULL) /* If bad file pointer, give up */ { error(PER_OPEN,"%s",filnam); /* Can't open file */ if (!get_file_spec(FALSE)) return('C'); /* No more files to do */ else return('S'); /* Try next file */ } for (i = strlen(filnam) - 1; i >= 0; --i) if (filnam[i] == '/') /* Skip directory specification */ break; strcpy(fnm,&filnam[i+1]); map_case(fnm,OUT); /* map to correct case */ if (!nooutput) { if (screen) { disp(0,2,"Sending: "); posit(20,2); printf("%s as %s", filnam, fnm); clreol(-1,-1); } else printf("\n\lSending: %s as %s\n\l",filnam,fnm); } fnm[strlen(fnm)] = EOF; /* Terminate data */ len = bufill(sndpkt,TRUE,fnm); spack('F',n,len,sndpkt,0,block_check_type); /* Send an F packet */ switch(rpack(&len,&num,recpkt,block_check_type))/* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num < 0 ? 63 : num); /* unless it's NAK for next packet */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) /* If wrong ACK, stay in F state */ return(state); numtry = 0; /* Reset try counter */ n = (n + 1) % 64; /* Bump packet count */ if (attribute) return('A'); /* Switch to attribute state */ else { if ((size = bufill(sndpkt,TRUE,0)) == EOF)/* data from file */ return('Z'); /* If EOF then empty data file */ org_size = size; /* Remember original size */ return('D'); /* Switch state to D */ } case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* abort */ case 'T': /* Timeout */ if (aborted) { error(PER_ABORTED); /* send error packet */ return('Q'); /* aborted by user */ } case FALSE: /* Receive failure, stay in F */ return(state); default: /* Something else, just "abort" */ return('Q'); } } /* * s a t t r * * Send File Attributes */ char sattr() { char num; /* Packet number */ int len; /* length */ if (numtry++ >= maxtry) /* If too many tries "abort" */ return('Q'); snd_attributes(); /* Prepare send attribute packet */ spack('A',n,size,sndpkt,0,block_check_type);/* Send an A packet */ switch (rpack(&len,&num,recpkt,block_check_type))/* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num < 0 ? 63 : num); /* unless NAK for previous packet, */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) /* If wrong ACK, fail */ return(state); numtry = 0; /* Reset try counter */ n = (n + 1) % 64; /* and bump packet count */ if ((size = bufill(sndpkt,TRUE,0)) == EOF)/* Get data from file */ return('Z'); /* If EOF then empty data file */ org_size = size; /* Remember original size */ return('D'); /* Switch state to data */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* abort */ case 'T': /* Timeout */ if (aborted) { error(PER_ABORTED); /* send error packet */ return('Q'); /* aborted by user */ } case FALSE: /* Receive failure, stay in B */ return(state); default: /* Other, "abort" */ return ('Q'); } } /* * s d a t a * * Send File Data */ char sdata() { char num, /* Packet number */ tmpc; int len; /* length */ if (numtry++ >= maxtry) /* If too many tries, give up */ return('Q'); spack('D',n,size,sndpkt,offset,block_check_type);/* Send a D packet */ switch(rpack(&len,&num,recpkt,block_check_type))/* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num < 0 ? 63 : num); /* unless it's NAK for next packet */ if (n != num) /* which is just like an ACK for */ { /* this packet so fall thru to 'Y' */ if ((org_size > 91) && auto_recover)/* If extended length... */ lower_size(); /* Lower packet size on error */ return(state); /* Try again */ } case 'Y': /* ACK */ if (n != num) /* If wrong ACK, fail */ return(state); numtry = 0; /* Reset try counter */ n = (n + 1) % 64; /* Bump packet count */ if (size_lowered) adjust_size(); /* Still data in buffer */ else { offset = 0; /* No more old data in buffer */ if ((size = bufill(sndpkt,FALSE,0)) == EOF)/* Get new data */ return('Z'); /* If EOF set state to that */ org_size = size; /* Remember original size */ } tmpc = *recpkt; if (len == 1) /* Data on ack */ { if (tmpc == 'Z') /* Stop entire batch */ filecount = 0; /* No more files to send */ if ((tmpc == 'X') || (tmpc == 'Z')) aborted = tmpc - 64; /* Make binary */ } if ((aborted == ABORTX) || (aborted == ABORTZ)) { if (screen) disp(0,19,"Transfer interrupted."); else fputs("Transfer interrupted.\n\l",stdout); beep(); return('Z'); /* Send abort */ } return('D'); /* Got data, stay in state D */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* abort */ case 'T': /* Timeout */ if (aborted) { error(PER_ABORTED); /* send error packet */ return('Q'); /* aborted by user */ } if ((org_size > 91) && auto_recover) /* If extended length... */ lower_size(); /* Lower packet size on error */ case FALSE: /* Receive failure, stay in D */ return(state); default: /* Anything else, "abort" */ return('Q'); } } /* * s e o f * * Send End-Of-File. */ char seof() { char num; /* Packet number */ int len, tlen; /* length */ if (numtry++ >= maxtry) /* If too many tries, "abort" */ return('Q'); tlen = 0; /* Assume no abort */ if ((aborted == ABORTX) || (aborted == ABORTZ)) { *sndpkt = 'D'; /* Discard file on abort */ tlen = 1; *(sndpkt+sizeof(char)) = '\0'; /* For debug printout */ } spack('Z',n,tlen,sndpkt,0,block_check_type); /* Send a 'Z' packet */ switch(rpack(&len,&num,recpkt,block_check_type))/* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num < 0 ? 63 : num); /* unless it's NAK for next packet */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) /* If wrong ACK, hold out */ return(state); numtry = 0; /* Reset try counter */ n = (n + 1) % 64; /* and bump packet count */ fclose(fp); /* Close the input file */ fp = ERROR; /* flag no file open */ if (!get_file_spec(FALSE)) return ('B'); /* Stop if no more files */ if (aborted == ABORTZ) /* Abort the rest ? */ { while (get_file_spec(FALSE)); /* Flush directory buffer */ return ('B'); } return('F'); /* More files, switch state to F */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* abort */ case 'T': /* Timeout */ if (aborted) { error(PER_ABORTED); /* send error packet */ return('Q'); /* aborted by user */ } case FALSE: /* Receive failure, stay in Z */ return(state); default: /* Something else, "abort" */ return('Q'); } } /* * s b r e a k * * Send Break (EOT) */ char sbreak() { char num; /* Packet number */ int len; /* length */ if (numtry++ >= maxtry) /* If too many tries "abort" */ return('Q'); spack('B',n,0,sndpkt,0,block_check_type);/* Send a B packet */ switch (rpack(&len,&num,recpkt,block_check_type))/* What was the reply? */ { case 'N': /* NAK, just stay in this state, */ num = (--num < 0 ? 63 : num); /* unless NAK for previous packet, */ if (n != num) /* which is just like an ACK for */ return(state); /* this packet so fall thru to... */ case 'Y': /* ACK */ if (n != num) /* If wrong ACK, fail */ return(state); numtry = 0; /* Reset try counter */ n = (n + 1) % 64; /* and bump packet count */ return('C'); /* Switch state to Complete */ case 'E': /* Error packet received */ prerrpkt(recpkt); /* Print it out and */ return('Q'); /* abort */ case 'T': /* Timeout */ if (aborted) { error(PER_ABORTED); /* send error packet */ return('Q'); /* aborted by user */ } case FALSE: /* Receive failure, stay in B */ return(state); default: /* Other, "abort" */ return ('Q'); } } lower_size() { int rest; if (size >= 80) /* Minimum size to cut packet size to */ { rest = size % 2; /* Find out if odd or even */ size /= 2; /* Half of it */ size += rest; /* Add rest if odd */ spsiz = size; /* Use the new size from now on */ size_lowered = TRUE; /* Flag size has been modified */ check_prefix(); /* Make sure not in middle of prefix sequence */ } } adjust_size() { offset += size; /* Increment offset to next unsend character */ if (offset + size >= org_size) /* Adjust size if past end of buffer */ { size = org_size - offset; size_lowered = FALSE; /* Flag modification done */ } else check_prefix(); /* Make sure not in middle of prefix sequence */ } check_prefix() { register char *p; char *q; p = sndpkt + offset; /* Start check at this place */ q = p + size; /* Until end of current window */ while (p < q) { if (*p == repeat_quote) /* If it's a repeat quote character .. */ p += 2 * sizeof(char); /* Skip count */ if (*p == eight_quote) /* If it's an eight-bit quote */ p++; /* Skip it */ if (*p == quote) /* Same for control quote character */ p++; p++; /* Point to next data character */ } size = p - (sndpkt + offset); /* Calculate new size */ }