/*--------------------------------------------------------------------------*/ /* */ /* */ /* ------------ Bit-Bucket Software, Co. */ /* \ 10001101 / Writers and Distributors of */ /* \ 011110 / Freely Available Software. */ /* \ 1011 / */ /* ------ */ /* */ /* (C) Copyright 1987-96, Bit Bucket Software Co. */ /* */ /* This module was written by Bob Hartman */ /* */ /* BinkleyTerm Xmodem Receiver State Machine */ /* */ /* */ /* For complete details of the licensing restrictions, please refer */ /* to the License agreement, which is published in its entirety in */ /* the MAKEFILE and BT.C, and also contained in the file LICENSE.260. */ /* */ /* USE OF THIS FILE IS SUBJECT TO THE RESTRICTIONS CONTAINED IN THE */ /* BINKLEYTERM LICENSING AGREEMENT. IF YOU DO NOT FIND THE TEXT OF */ /* THIS AGREEMENT IN ANY OF THE AFOREMENTIONED FILES, OR IF YOU DO */ /* NOT HAVE THESE FILES, YOU SHOULD IMMEDIATELY CONTACT BIT BUCKET */ /* SOFTWARE CO. AT ONE OF THE ADDRESSES LISTED BELOW. IN NO EVENT */ /* SHOULD YOU PROCEED TO USE THIS FILE WITHOUT HAVING ACCEPTED THE */ /* TERMS OF THE BINKLEYTERM LICENSING AGREEMENT, OR SUCH OTHER */ /* AGREEMENT AS YOU ARE ABLE TO REACH WITH BIT BUCKET SOFTWARE, CO. */ /* */ /* */ /* You can contact Bit Bucket Software Co. at any one of the following */ /* addresses: */ /* */ /* Bit Bucket Software Co. FidoNet 1:104/501, 1:343/491 */ /* P.O. Box 460398 AlterNet 7:42/1491 */ /* Aurora, CO 80046 BBS-Net 86:2030/1 */ /* Internet f491.n343.z1.fidonet.org */ /* */ /* Please feel free to contact us at any time to share your comments about */ /* our software and/or licensing policies. */ /* */ /*--------------------------------------------------------------------------*/ /* Include this file before any other includes or defines! */ #include "includes.h" void Find_Char (int); int Header_in_data (unsigned char *); void Send_ACK (XMARGSP); void Send_NAK (XMARGSP); long Open_Xmodem_File (XMARGSP); int XRInit (XMARGSP); int XREnd (XMARGSP); int XRRecInit (XMARGSP); int XRBrecInit (XMARGSP); int XRRecStart (XMARGSP); int XRWaitFirst (XMARGSP); int XRWaitBlock (XMARGSP); int XRRestart (XMARGSP); int XRSetOvrdr (XMARGSP); typedef struct { char *state_name; int (*state_func) (XMARGSP); } XSTATES, *XSTATEP; XSTATES Xmodem_Receiver[] = { {"XRInit", XRInit}, {"XREnd", XREnd}, {"XR0", XRRecInit}, {"XR0B", XRBrecInit}, {"XR1", XRRecStart}, {"XR2", XRWaitFirst}, {"XR3", XRWaitBlock}, {"XR4", XRRestart}, {"XR5", XRSetOvrdr} }; long Open_Xmodem_File (XMARGSP args) { char *s1, *s2; if (args->file_pointer == NULL) { args->temp_name = calloc (1, 80); if (args->path != NULL) (void) strcpy (args->temp_name, args->path); s1 = &(args->temp_name[strlen (args->temp_name)]); (void) strcpy (s1, "BTXXXXXX"); s2 = mktemp (args->temp_name); if ((s2 == NULL) || ((args->file_pointer = fopen (s2, write_binary)) == NULL)) { status_line (MSG_TXT (M_TEMP_NOT_OPEN), s2); return (-1L); } } throughput (0, 0L); return (0L); } long Set_Up_Restart (XMARGSP args) { char foo[100]; char foo1[50]; struct stat st; args->sub_results = 0; /* Look for file in directory */ if (args->path != NULL) (void) strcpy (foo, args->path); if ((args->received_name != NULL) && (strlen (args->received_name) > 0) && args->options.Resync) { (void) strcat (foo, args->received_name); if (stat (foo, &st) == 0) { if ((st.st_size == args->filelen) && (st.st_atime == (time_t) (args->save_filetime.oneword.timedate))) { if ((args->file_pointer = fopen (foo, "rb+")) != NULL) { throughput (0, 0L); (void) fseek (args->file_pointer, 0L, SEEK_END); args->sub_results = DID_RESYNC; args->temp_name = calloc (1, 80); (void) strcpy (args->temp_name, foo); args->prev_bytes = args->filelen; status_line (MSG_TXT (M_ALREADY_HAVE), foo); status_line (MSG_TXT (M_SYNCHRONIZING_EOF)); return (args->total_blocks + 1L); } } } /* Look for file in .Z file */ if (dexists (Abortlog_name)) { (void) sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate); if (check_failed (Abortlog_name, args->received_name, Resume_info, foo1)) { foo[0] = '\0'; /* Here it looks like it was a failed WaZOO session */ if (args->path != NULL) (void) strcpy (foo, args->path); (void) strcat (foo, foo1); if ((args->file_pointer = fopen (foo, "rb+")) != NULL) { (void) stat (foo, &st); throughput (0, 0L); args->temp_name = calloc (1, 80); (void) strcpy (args->temp_name, foo); args->prev_bytes = (st.st_size / 128L) * 128L; (void) fseek (args->file_pointer, args->prev_bytes, SEEK_SET); status_line (MSG_TXT (M_SYNCHRONIZING_OFFSET), args->prev_bytes); return (args->prev_bytes / 128L + 1L); } } } } return (Open_Xmodem_File (args)); } void Finish_Xmodem_Receive (XMARGSP args) { struct stat st; char new_name[80]; struct utimbuf times; int i, j, k; /* Set the file's time and date stamp */ if ((args->save_header == SOH) || (args->save_header == SYN)) { (void) fclose (args->file_pointer); times.modtime = times.UT_ACTIME = (time_t) args->save_filetime.oneword.timedate; (void) utime (args->temp_name, (UTIMBUF *) & times); } else { (void) strcpy (args->received_name, ""); if (args->file_pointer) (void) fclose (args->file_pointer); } if (args->result == SUCCESS) { long lFileTime; long lFileSize; /* Get the file information */ (void) stat (args->temp_name, &st); lFileSize = st.st_size - args->prev_bytes; lFileTime = throughput (1, (unsigned long)lFileSize); if (args->sub_results & DID_RESYNC) { status_line ("%s: %s", MSG_TXT (M_FILE_RECEIVED), args->temp_name); update_files (0, args->temp_name, lFileSize, lFileTime, 0); } else { new_name[0] = '\0'; if (args->path != NULL) (void) strcpy (new_name, args->path); if ((args->filename == NULL) || (strlen (args->filename) == 0)) { if (strlen (args->received_name) > 0) (void) strcat (new_name, args->received_name); else (void) strcat (new_name, "BAD_FILE.000"); } else { (void) strcat (new_name, args->filename); } i = (int) strlen (args->temp_name) - 1; j = (int) strlen (new_name) - 1; if (args->temp_name[i] == '.') args->temp_name[i] = '\0'; if (new_name[j] == '.') { new_name[j] = '\0'; --j; } i = 0; k = is_arcmail (new_name, j); status_line ("%s: %s", MSG_TXT (M_FILE_RECEIVED), new_name); update_files (0, new_name, lFileSize, lFileTime, 0); if ((!overwrite) || k) { while (rename (args->temp_name, new_name)) { if (isdigit (new_name[j])) new_name[j]++; else new_name[j] = '0'; if (!isdigit (new_name[j])) { return; } i = 1; } CLEAR_IOERR (); } else { (void) unlink (new_name); while (rename (args->temp_name, new_name)) { if (!i) { status_line (MSG_TXT (M_ORIGINAL_NAME_BAD), new_name); } if (isdigit (new_name[j])) new_name[j]++; else new_name[j] = '0'; if (!isdigit (new_name[j])) { return; } i = 1; } CLEAR_IOERR (); } if (i) { if (locate_y && !(fullscreen && un_attended)) gotoxy (2, locate_y - 1); status_line (MSG_TXT (M_RENAME_MSG), new_name); } } remove_abort (Abortlog_name, args->received_name); } else { if ((args->received_name != NULL) && (strlen (args->received_name) > 0) && (args->save_header != 0)) { (void) sprintf (Resume_info, "%ld %lo", args->filelen, args->save_filetime.oneword.timedate); add_abort (Abortlog_name, args->received_name, args->temp_name, args->path, Resume_info); } else { /* File aborted, so remove all traces of it */ if (args->temp_name != NULL) (void) unlink (args->temp_name); } } if (args->temp_name != NULL) { free (args->temp_name); } } void Get_Telink_Info (XMARGSP args) { char *p1; char junkbuff[100]; TLDATAP t; unsigned int i, j; struct tm tmstruc; time_t curr_time; /* Figure out how many blocks we will get */ t = (TLDATAP) & (args->header); args->total_blocks = (t->filelength + 127) / 128; t->nullbyte = '\0'; p1 = strchr (t->filename, ' '); if (p1 != NULL) *p1 = '\0'; /* Rename .REQ files */ i = strlen (t->filename) - 4; if ((i > 0) && (stricmp (&(t->filename)[i], ".REQ") == 0)) { (t->filename)[i] = '\0'; status_line (MSG_TXT(M_REC_REQ_AS), t->filename, t->filename, TaskNumber); sprintf (&(t->filename)[i],".R%02x", TaskNumber); } (void) strcpy (args->received_name, t->filename); args->save_header = args->header; if (args->save_header == SYN) { i = t->filetime.twowords.time; j = t->filetime.twowords.date; curr_time = time (NULL); tmstruc = *localtime (&curr_time); /* Structure assignment */ tmstruc.tm_year = (j >> 9) + 80; tmstruc.tm_mon = ((j >> 5) & 0x0f) - 1; tmstruc.tm_mday = j & 0x1f; tmstruc.tm_hour = i >> 11; tmstruc.tm_min = (i >> 5) & 0x3f; tmstruc.tm_sec = i & 0x1f; args->save_filetime.oneword.timedate = mktime (&tmstruc); } else { #ifdef ANSI_TIME_T args->save_filetime.oneword.timedate = t->filetime.oneword.timedate + ANSI_TIME_T_DELTA; #else args->save_filetime.oneword.timedate = t->filetime.oneword.timedate; #endif } args->filelen = t->filelength; (void) sprintf (junkbuff, MSG_TXT (M_RECEIVE_MSG), args->total_blocks, t->filename, t->sendingprog, t->filelength); (void) strncpy (args->sending_program, t->sendingprog, 15); if (un_attended && fullscreen) { clear_filetransfer (); sb_move (filewin, 1, 2); sb_puts (filewin, junkbuff); elapse_time (); sb_show (); } else { status_line ("+%s", junkbuff); (void) printf ("\n"); locate_y = wherey (); locate_x = wherex (); } } int Read_Block (XMARGSP args) { unsigned char *p; /* Pointers to XMODEM data */ int i; /* Counter */ int j; /* Counter start */ unsigned char c; /* character being processed */ int in_char; char junkbuff[128]; long head_timer; struct _pkthdr *packet; /* FTS-0001 packet type */ struct _pkthdr45 *pkt0045; /* FSC-0045 packet type */ struct _pkthdr39 *pkt0039; /* FSC-0039 packet type */ unsigned int cwtest; /* Used to verify FSC-0039 type */ if (got_ESC ()) { status_line (MSG_TXT (M_KBD_MSG)); return (KBD_ERR); } /* Set up to point into the XMODEM data structure */ p = (unsigned char *) &(args->header); /* Get the first character that is waiting */ *p = (unsigned char) TIMED_READ (8); head_timer = timerset (6000); j = 1; while (!timeup (head_timer)) { /* Now key off of the header character */ switch (*p) { case EOT: /* End of file */ /* Is this a valid EOT */ if (args->total_blocks <= args->WriteBLK) { return (EOT_BLOCK); } else { status_line (MSG_TXT (M_UNEXPECTED_EOF), args->total_blocks); return (BAD_BLOCK); } case SYN: /* Telink block */ /* For Telink, read all of the data except the checksum */ for (i = 1; i < sizeof (TLDATA) - 2; i++) { /* If we go more than 5 second, then we have a short block */ if ((in_char = TIMED_READ (5)) < 0) { return (BAD_BLOCK); } *(++p) = (unsigned char) (in_char & 0xff); } /* if the block number or its complement are wrong, return error */ if ((args->block_num != 0) || (args->block_num_comp != 0xff)) { return (BAD_BLOCK); } /* Now calculate the checksum - Telink block always checksum mode */ Data_Check ((XMDATAP) & (args->header), CHECKSUM); /* See if we can receive the checksum byte */ if ((in_char = TIMED_READ (10)) < 0) { Xmodem_Error (MSG_TXT (M_TIMEOUT), 0L); return (BAD_BLOCK); } /* Was it right */ c = (unsigned char) (in_char & 0xff); if (c != args->data_check[0]) { Xmodem_Error (MSG_TXT (M_CHECKSUM), 0L); return (BAD_BLOCK); } /* Everything looks good, it must be a legal TELINK block */ Get_Telink_Info (args); return (TELINK_BLOCK); case SOH: /* Normal data block */ args->datalen = 128; /* Read in all of the data for an XMODEM block except the checksum */ p += (j - 1); for (i = j; i < sizeof (XMDATA) - 2; i++) { /* If we go more than 5 seconds, then it is a short block */ if ((in_char = TIMED_READ (5)) < 0) { return (BAD_BLOCK); } *(++p) = (unsigned char) (in_char & 0xff); } /* The block number is 0 to 255 inclusive */ c = (unsigned char) (args->blocknum & 0xff); /* Properly calculate the CRC or checksum */ Data_Check ((XMDATAP) & (args->header), args->options.do_CRC ? CRC : CHECKSUM); /* Can we get the checksum byte */ if ((in_char = TIMED_READ (10)) < 0) { Xmodem_Error (MSG_TXT (M_TIMEOUT), args->WriteBLK); return (BAD_BLOCK); } /* Is it the right value */ c = (unsigned char) (in_char & 0xff); if (c != args->data_check[0]) { status_line (">Xmodem Receive: Bad %s", (args->options.do_CRC) ? "CRC" : "checksum"); Xmodem_Error (MSG_TXT (M_CRC_MSG), args->WriteBLK); if (args->options.do_CRC) (void) TIMED_READ (5); return (BAD_BLOCK); } /* If we are in CRC mode, do the second byte */ if (args->options.do_CRC) { /* Can we get the character */ if ((in_char = TIMED_READ (10)) < 0) { status_line (">Xmodem Receive: Timeout waiting for CRC byte 2"); Xmodem_Error (MSG_TXT (M_TIMEOUT), args->WriteBLK); return (BAD_BLOCK); } /* Is it right */ c = (unsigned char) (in_char & 0xff); if (c != args->data_check[1]) { Xmodem_Error (MSG_TXT (M_CRC_MSG), args->WriteBLK); return (BAD_BLOCK); } } /* Do we have a valid data block */ if (args->block_num_comp != (unsigned char) ((~(args->block_num)) & 0xff)) { if (!(args->options.SEAlink)) { Xmodem_Error (MSG_TXT (M_JUNK_BLOCK), args->WriteBLK); return (BAD_BLOCK); } p = (unsigned char *) &(args->header); j = Header_in_data (p); if (j) { continue; } j = 1; Find_Char (SOH); *p = (unsigned char) TIMED_READ (0); } if ((args->WriteBLK == 1) && (args->header == SOH) && (args->block_num == 0)) { Get_Telink_Info (args); return (SEALINK_BLOCK); } if (first_block) { packet = (struct _pkthdr *) args->data; pkt0045 = (struct _pkthdr45 *) packet; pkt0039 = (struct _pkthdr39 *) packet; if (!remote_capabilities) { remote_addr.Net = packet->orig_net; remote_addr.Node = packet->orig_node; if (packet->rate == 2) { /* This is a FSC-0045 (type 2.2) packet! */ remote_addr.Zone = packet->orig_zone; remote_addr.Point = (unsigned) pkt0045->orig_point; strncpy (junkbuff, (char *) (pkt0045->orig_domain), 8); junkbuff[8] = '\0'; remote_addr.Domain = find_domain (junkbuff); } else { remote_addr.Domain = NULL; cwtest = (((pkt0039->CapValid) & 0x7f00) >> 8) + (((pkt0039->CapValid) & 0x007f) << 8); if (cwtest == (unsigned int) ((pkt0039->CapWord) & 0x7f7f)) { /* This is a FSC-0039 packet! */ remote_addr.Zone = pkt0039->orig_zone; remote_addr.Point = pkt0039->orig_point; } else { remote_addr.Zone = packet->orig_zone; remote_addr.Point = 0; } } /* * Here we have extracted the Zone, Net, Node, Point and Domain from the * packet -- regardless of type. Now see if we need to map to a fake net * or to mung the address because it's someone else's point. */ if ((remote_addr.Point > 0) && (pvtnet >= 0) && ((remote_addr.Zone == alias[assumed].Zone) || (remote_addr.Zone == 0)) && (remote_addr.Net == boss_addr.Net) && (remote_addr.Node == boss_addr.Node)) { remote_addr.Net = pvtnet; remote_addr.Node = remote_addr.Point; remote_addr.Point = 0; } else if ((pvtnet >= 0) && (remote_addr.Point > 0)) { remote_addr.Point = 0; remote_addr.Node = (unsigned short) -1; } } if (who_is_he) { if (!remote_addr.Zone && !remote_addr.Net && !remote_addr.Node) { LOWER_DTR (); /* Bad trip, cut it off */ timer (2); /* Wait two secs */ return (CARRIER_ERR); /* Get out of here! */ } if (nodefind (&remote_addr, 1)) { if (!remote_addr.Zone) remote_addr.Zone = found_zone; (void) sprintf (junkbuff, "%s: %s (%s)", MSG_TXT (M_REMOTE_SYSTEM), newnodedes.SystemName, Full_Addr_Str (&remote_addr)); } else { (void) sprintf (junkbuff, "%s: %s (%s)", MSG_TXT (M_REMOTE_SYSTEM), MSG_TXT (M_UNKNOWN_MAILER), Full_Addr_Str (&remote_addr)); } last_type (2, &remote_addr); status_line (junkbuff); } if (args->sending_program[0] != '\0') { status_line ("%s %s", MSG_TXT (M_REMOTE_USES), args->sending_program); } else { log_product (packet->product, 0, packet->serial); } who_is_he = 0; first_block = 0; } if (args->WriteBLK == args->total_blocks) { args->datalen = (int) (args->filelen - ((args->WriteBLK - 1) * 128)); } /* If we got this far, it is a valid data block */ args->recblock = args->block_num; return (XMODEM_BLOCK); default: /* Bad block */ if ((args->blocknum <= 1) || (PEEKBYTE () < 0)) return (BAD_BLOCK); /* Garbage header, return bad */ *p = (unsigned char) TIMED_READ (0); } } return (BAD_BLOCK); } int XRInit (XMARGSP args) { char *HoldName; args->tries = 0; args->goodfile = 1; XON_DISABLE (); HoldName = HoldAreaNameMunge (&called_addr); (void) sprintf (Abortlog_name, "%s%s.Z\0", HoldName, Hex_Addr_Str (&remote_addr)); args->sending_program[0] = '\0'; return ((int) args->control); } int XREnd (XMARGSP args) { args->result = (int) args->control; Finish_Xmodem_Receive (args); return ((int) args->control); } int XRRecInit (XMARGSP args) { args->options.SEAlink = 0; args->options.SLO = 0; args->options.Resync = 0; args->options.MacFlow = 0; args->options.do_CRC = 1; args->blocknum = 0; args->WriteBLK = 1; args->curr_byte = 0L; args->tries = 0; return (XR1); } int XRBrecInit (XMARGSP args) { args->options.SEAlink = 0; args->options.SLO = 0; args->options.Resync = 0; args->options.MacFlow = 0; args->options.do_CRC = 1; args->blocknum = 0; args->WriteBLK = 1; args->curr_byte = 0L; args->tries = 0; return (XR2); } int XRRecStart (XMARGSP args) { Send_NAK (args); return (XR2); } int XRWaitFirst (XMARGSP args) { long XR2Timer; XR2Timer = timerset (800); if (args->tries >= 10) { args->goodfile = 0; return (TIME_ERR); } if (args->tries == 5) { args->options.do_CRC = 0; ++(args->tries); return (XR1); } while (CARRIER) { switch (Read_Block (args)) { case EOT_BLOCK: args->WriteBLK = 0; Send_ACK (args); return (SUCCESS_EOT); case TELINK_BLOCK: if (Open_Xmodem_File (args) == -1L) return (OPEN_ERR); Send_ACK (args); args->tries = 0; return (XR3); case SEALINK_BLOCK: args->options.SEAlink = no_sealink ? 0 : 1; if (args->options.SEAlink && !no_resync) args->options.Resync = (((SEADATAP) (&(args->header)))->Resync) != 0; return (XR4); case XMODEM_BLOCK: if (args->recblock == 1) { if (Open_Xmodem_File (args) == -1L) return (OPEN_ERR); (void) fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer); ++(args->WriteBLK); args->curr_byte = 128L; ++(args->blocknum); Send_ACK (args); args->tries = 0; return (XR3); } /* Fallthrough on wrong block */ case BAD_BLOCK: ++(args->tries); return (XR1); case CARRIER_ERR: case KBD_ERR: return (CARRIER_ERR); } if (timeup (XR2Timer)) { ++(args->tries); return (XR1); } } return (CARRIER_ERR); } int XRWaitBlock (XMARGSP args) { int blocknum_copy; if (args->tries >= 10) { args->goodfile = 0; return (TIME_ERR); } while (CARRIER) { switch (Read_Block (args)) { case EOT_BLOCK: args->options.SLO = 0; Send_ACK (args); return (SUCCESS); case XMODEM_BLOCK: blocknum_copy = (int) args->blocknum & 0xff; if (args->recblock == ((blocknum_copy - 1) & 0xff)) { --(args->blocknum); Send_ACK (args); return (XR3); } if (args->recblock == blocknum_copy) { (void) fwrite (args->data, sizeof (unsigned char), args->datalen, args->file_pointer); ++(args->WriteBLK); args->curr_byte += 128L; Send_ACK (args); args->tries = 0; return (XR3); } if (args->recblock < blocknum_copy) { args->recblock += 256; } if ((args->recblock > blocknum_copy) && (args->recblock <= ((blocknum_copy + 127) & 0xff))) { if (args->tries != 0) { /* We have sent at least one nak, now only send them every so often to allow buffers to drain */ if ((args->recblock - blocknum_copy) % 16) return (XR3); /* If it is a multiple of 16, then check that it is higher than 32 */ if ((args->recblock - blocknum_copy) / 16 < 2) return (XR3); } } /* fallthrough on bad block */ case BAD_BLOCK: Send_NAK (args); ++(args->tries); return (XR3); case CARRIER_ERR: case KBD_ERR: return (CARRIER_ERR); } } return (CARRIER_ERR); } int XRRestart (XMARGSP args) { long c; c = Set_Up_Restart (args); if (c == -1L) return (OPEN_ERR); if ((!c) || (!(args->options.Resync))) { Send_ACK (args); args->tries = 0; } else { args->WriteBLK = c; args->curr_byte = (c - 1) * 128L; args->blocknum = (unsigned char) ((args->WriteBLK) & 0xff); Send_NAK (args); } return (XR5); } int XRSetOvrdr (XMARGSP args) { if (!no_overdrive) args->options.SLO = (((SEADATAP) (&(args->header)))->SLO) != 0; if (args->options.SLO) show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args); return (XR3); } int Xmodem_Receive_File (char *path, char *filename) { XMARGS xmfile; int res; locate_y = wherey (); locate_x = wherex (); (void) memset (&xmfile, 0, sizeof (XMARGS)); xmfile.path = path; xmfile.filename = filename; xmfile.total_blocks = -1L; xmfile.sent_ACK = 0; res = state_machine ((STATEP) Xmodem_Receiver, &xmfile, XR0); return (res); } int Batch_Xmodem_Receive_File (char *path, char *filename) { XMARGS xmfile; int res; locate_y = wherey (); locate_x = wherex (); (void) memset (&xmfile, 0, sizeof (XMARGS)); xmfile.path = path; xmfile.filename = filename; xmfile.total_blocks = -1L; xmfile.sent_ACK = 0; res = state_machine ((STATEP) Xmodem_Receiver, &xmfile, XR0B); return (res); } int SAInit (XMARGSP); int SAEnd (XMARGSP); int SAClearLine (XMARGSP); int SASendACK (XMARGSP); int SASEAlink (XMARGSP); int SAIncBlk (XMARGSP); typedef struct { char *state_name; int (*state_func) (XMARGSP); } ASTATES, *ASTATEP; ASTATES ACK_States[] = { {"SAInit", SAInit}, {"SAEnd", SAEnd}, {"SA0", SAClearLine}, {"SA1", SASendACK}, {"SA2", SASEAlink}, {"SA3", SAIncBlk} }; int SAInit (XMARGSP args) { return ((int) args->control); } int SAEnd (XMARGSP args) { return ((int) args->control); } int SAClearLine (XMARGSP args) { long SA0Timer; SA0Timer = timerset (3000); if (args->options.SLO) return (SA3); if (args->options.SEAlink) return (SA1); while (CARRIER && !timeup (SA0Timer)) { if (PEEKBYTE () >= 0) { (void) TIMED_READ (0); time_release (); continue; } return (SA1); } return (TIME_ERR); } int SASendACK (XMARGSP args) { SENDBYTE (ACK); args->sent_ACK = 1; return (SA2); } int SASEAlink (XMARGSP args) { if (!(args->options.SEAlink)) return (SA3); SENDBYTE (args->blocknum); SENDBYTE ((unsigned char) ~(args->blocknum)); return (SA3); } void show_block (long b, char *c, XMARGSP args) { char j[100]; long k; if (fullscreen && un_attended) { elapse_time (); sb_move (filewin, 2, 2); sb_puts (filewin, ultoa (((unsigned long) b), e_input, 10)); if (c) sb_puts (filewin, c); k = args->filelen - args->curr_byte; if (k < 0L) k = 0L; (void) sprintf (j, "%3ld min", ((k * 10L / cur_baud.rate_value * 100L / ((args->save_header == SOH) ? 94L : 70L) + 59L) / 60L)); sb_move (filewin, 2, 69); sb_puts (filewin, j); sb_show (); } else { gotoxy (locate_x, locate_y); (void) printf ("%s", ultoa (((unsigned long) b), e_input, 10)); if (c) (void) printf ("%s", c); } } int SAIncBlk (XMARGSP args) { ++(args->blocknum); if ((args->options.SLO) && (((args->WriteBLK > 0) && (!((args->WriteBLK - 1) & 0x001F)) && (args->WriteBLK < args->total_blocks)) || (args->WriteBLK >= args->total_blocks))) { show_block ((long) (args->WriteBLK - 1), " *Overdrive*", args); } else if ((!(args->options.SLO)) && (args->WriteBLK > 0)) { show_block ((long) (args->WriteBLK - 1), NULL, args); } return (SUCCESS); } void Send_ACK (XMARGSP args) { (void) state_machine ((STATEP) ACK_States, args, SA0); } void Send_Resync_Packet (XMARGSP); int SNInit (XMARGSP); int SNEnd (XMARGSP); int SNClearLine (XMARGSP); int SNSendNAK (XMARGSP); int SNSEAlink (XMARGSP); int SNAckResync (XMARGSP); typedef struct { char *state_name; int (*state_func) (XMARGSP); } NSTATES, *NSTATEP; NSTATES NAK_States[] = { {"SNInit", SNInit}, {"SNEnd", SNEnd}, {"SN0", SNClearLine}, {"SN1", SNSendNAK}, {"SN2", SNSEAlink}, {"SN3", SNAckResync} }; int SNInit (XMARGSP args) { return ((int) args->control); } int SNEnd (XMARGSP args) { return ((int) args->control); } int SNClearLine (XMARGSP args) { long SN0Timer; SN0Timer = timerset (3000); if (args->options.Resync) { Send_Resync_Packet (args); return (SN3); } if (args->options.SEAlink) return (SN1); while (CARRIER && !timeup (SN0Timer)) { if (PEEKBYTE () >= 0) { (void) TIMED_READ (0); time_release (); continue; } return (SN1); } return (TIME_ERR); } int SNSendNAK (XMARGSP args) { if (args->options.do_CRC && (args->sent_ACK == 0)) SENDBYTE (WANTCRC); else SENDBYTE (NAK); return (SN2); } int SNSEAlink (XMARGSP args) { if (!(args->options.SEAlink)) return (SUCCESS); SENDBYTE (args->blocknum); SENDBYTE ((unsigned char) ~(args->blocknum)); return (SUCCESS); } int SNAckResync (XMARGSP args) { long SN3Timer; int c; SN3Timer = timerset (3000); while (CARRIER && !timeup (SN3Timer)) { if ((unsigned int) (c = TIMED_READ (10)) == 0xffff) { Send_Resync_Packet (args); continue; } if (c == ACK) { big_pause (1); c = PEEKBYTE (); if ((c == SOH) || (c == EOT)) return (SUCCESS); } } if (!CARRIER) return (CARRIER_ERR); else return (TIME_ERR); } void Send_NAK (XMARGSP args) { (void) state_machine ((STATEP) NAK_States, args, SN0); } void Send_Resync_Packet (XMARGSP args) { unsigned char resyncit[30]; unsigned short nak_crc; SENDBYTE (SYN); (void) sprintf ((char *) resyncit, "%ld", args->WriteBLK); SENDCHARS ((char *) resyncit, strlen ((char *) resyncit), 1); nak_crc = crc_block ((unsigned char *) resyncit, (int) strlen ((char *) resyncit)); SENDBYTE (ETX); SENDBYTE ((unsigned char) (nak_crc & 0xff)); CLEAR_INBOUND (); SENDBYTE ((unsigned char) (nak_crc >> 8)); } void Xmodem_Error (char *s, long block_number) { char j[50]; char k[50]; (void) sprintf (j, "%s %s %ld", s, MSG_TXT (M_ON_BLOCK), block_number); (void) sprintf (k, "%-49.49s", j); status_line (">Xmodem Error: %s", k); if (fullscreen && un_attended) { sb_move (filewin, 2, 20); sb_puts (filewin, k); sb_show (); } else { gotoxy (locate_x + 20, locate_y); (void) cputs (k); } } void Find_Char (int c) { long t1; long t2; t1 = timerset (3000); t2 = timerset (100); while (!timeup (t1) && !timeup (t2)) { if (!CARRIER) break; if (PEEKBYTE () == (c & 0xff)) break; else if (PEEKBYTE () >= 0) { (void) TIMED_READ (0); t2 = timerset (100); } } } int Header_in_data (unsigned char *p) { int i; int j; char *p1; p1 = (char *) p; ++p1; j = sizeof (XMDATA) - 2; for (i = 1; i < j; i++, p1++) { if (*p1 == SOH) { (void) memcpy (p, p1, (unsigned int) (j - i)); return (j - i); } } return (0); }