This is x_batch.c in view mode; [Download] [Up]
/*
* Routines to support the batch protocols.
*/
#include <stdio.h>
#include <ctype.h>
#include <curses.h>
#include "config.h"
#include "misc.h"
#include "xmodem.h"
/*
* Send the file name for the modem7 batch. Only uses 11 characters
* of the filename. Returns zero on success or the standard error codes.
*/
int
send_modem7(win, name)
WINDOW *win;
char *name;
{
char *new_name;
static char *fix_name();
unsigned char sum, calc_sum();
/* convert to 11 character name */
new_name = fix_name(name);
sum = calc_sum((unsigned char *) new_name, 12);
putc_line(ACK);
/* for each character in the name */
while (*new_name != CTRLZ) {
putc_line((unsigned char) *new_name);
switch (getc_line(3)) {
case -1: /* timed out */
clear_line(win, 12, 24, TRUE);
waddstr(win, "NO RESPONSE");
wrefresh(win);
return(ERROR);
case ACK: /* got it! */
break;
case CAN: /* cancel transmission */
if (getc_line(2) == CAN) {
beep();
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "REMOTE ABORTED");
wrefresh(win);
return(CANCEL);
}
/* fall thru... */
default:
clear_line(win, 12, 24, TRUE);
waddstr(win, "NAME FAILED");
wrefresh(win);
return(ERROR);
}
new_name++;
}
putc_line(CTRLZ);
/* verify the checksum */
if (getc_line(10) != sum) {
putc_line('u');
clear_line(win, 12, 24, TRUE);
waddstr(win, "CHECKSUM FAILED");
wrefresh(win);
return(ERROR);
}
putc_line(ACK);
return(0);
}
/*
* Receive a modem7 file name. Returns zero on success, the standard error
* codes, or a -1 on the end-of-batch. (Oddly enough, the end-of-batch code
* is the same as the code for a user abort)
*/
int
rcv_modem7(win, default_err)
WINDOW *win;
int default_err;
{
extern char file_name[15];
int i, j, err_method, err_count, got_it;
unsigned char sum, calc_sum();
char temp_name[13];
static void change_name(), unfix_name();
err_method = default_err;
if (default_err == CRC_CHECKSUM)
err_method = CRC;
err_count = 0;
got_it = 0;
while (err_count < MAX_ERRORS) {
/* switch to checksum? */
if (default_err == CRC_CHECKSUM && err_count > MAX_ERRORS/2)
err_method = CHECKSUM;
if (err_method == CRC)
putc_line('C');
else
putc_line(NAK);
/* what'd we get? */
switch (getc_line(10)) {
case -1: /* timed out */
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "NO RESPONSE");
wrefresh(win);
err_count++;
break;
case ACK: /* ready to go... */
got_it++;
break;
default: /* huh? */
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "BAD HEADER");
wrefresh(win);
err_count++;
}
if (got_it)
break;
}
if (!got_it)
return(ERROR);
/* get the name */
for (i=0; i<12; i++) {
j = getc_line(3);
switch (j) {
case -1: /* timed out */
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "NO RESPONSE");
wrefresh(win);
return(ERROR);
case EOT: /* end of batch? */
return(-1);
case CAN: /* cancel transmission */
if (getc_line(2) == CAN) {
beep();
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "REMOTE ABORTED");
wrefresh(win);
return(CANCEL);
}
/* fall thru... */
case 'u': /* bad name character */
beep();
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "BAD NAME");
wrefresh(win);
return(ERROR);
default: /* the name... */
temp_name[i] = j & 0xff;
if (j != CTRLZ)
putc_line(ACK);
break;
}
}
temp_name[12] = '\0';
/* send our checksum */
sum = calc_sum((unsigned char *) temp_name, 12);
putc_line(sum);
/* do they agree? */
if (getc_line(10) != ACK) {
beep();
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "BAD NAME");
wrefresh(win);
return(ERROR);
}
/* load the file_name array */
unfix_name(temp_name);
/* any name collisions? */
change_name(win, file_name);
return(0);
}
/*
* Send the block 0 information for a ymodem batch transfer. Uses only
* the name component of the path and the file size.
*/
int
send_ymodem(win, file, size)
WINDOW *win;
char *file;
long size;
{
unsigned short crc, calc_crc();
char *strcpy(), *memset();
unsigned char buf[133];
/* start with a clean block */
memset((char *) buf, '\0', 133);
/* the header */
buf[0] = SOH;
buf[1] = 0;
buf[2] = 255;
/*
* The block zero consists of the file name (no path component),
* a NULL, and the file length (as a string). The end of batch
* marker is an empty block.
*/
if (*file != '\0') {
strcpy((char *) &buf[3], file);
sprintf((char *) &buf[strlen(file)+4], "%ld", size);
}
/* the crc */
crc = calc_crc(&buf[3], 128);
buf[131] = crc >> 8;
buf[132] = crc;
/* the block count */
mvwaddstr(win, 7, 24, "0 ");
return(send_block(win, buf, 133));
}
/*
* Receive the block 0 information for a ymodem batch transfer. We
* only use the file name and the size (if present). Currently doesn't
* support full path names.
*/
int
rcv_ymodem(win)
WINDOW *win;
{
extern unsigned char buf[1029];
extern long file_length;
extern char file_name[15];
int code, length_is_at;
long atol();
static void change_name();
file_length = 0L;
file_name[0] = '\0';
/* read the zero block */
if (code = rcv_block(win, 1, 1024, 0))
return(code);
/* at end of batch */
if (buf[3] == '\0')
return(0);
/* get the file name */
change_name(win, (char *) &buf[3]);
/* any trouble? */
if (file_name[0] == '\0') {
putc_line(CAN);
return(0);
}
/*
* The file length is placed after the NULL of the file name
* and is terminated by another NULL. If the length is missing,
* atol() will see a NULL and return 0.
*/
length_is_at = strlen((char *) &buf[3]) + 4;
file_length = atol((char *) &buf[length_is_at]);
return(0);
}
/*
* Handle file name collisions. Prepend an "X" to the name until you find
* a name that doesn't already exist. Creates a NULL name on error.
* Loads the global character array "file_name".
*/
static void
change_name(win, str)
WINDOW *win;
char *str;
{
extern char file_name[15];
register int i;
int modified;
char temp[15], ans[15], *s, *strrchr(), *strcpy(), *strncat();
char *strncpy();
unsigned int sleep();
/* dissect the name component */
if ((s = strrchr(str, '/')))
strncpy(temp, ++s, 15);
else
strncpy(temp, str, 15);
temp[14] = '\0';
strcpy(ans, temp);
file_name[0] = '\0';
/* write permission on directory? */
if (access(".", 2)) {
beep();
clear_line(win, 12, 24, TRUE);
wattrstr(win, A_BOLD, "NO WRITE ON DIRECTORY");
wrefresh(win);
return;
}
/* prepend up to 13 "X"s */
modified = 0;
for (i=1; i<14; i++) {
if (access(ans, 0)) {
if (modified) {
beep();
clear_line(win, 12, 24, TRUE);
waddstr(win, "NAME COLLISION");
wrefresh(win);
sleep(1);
}
strcpy(file_name, ans);
return;
}
modified++;
strcpy(temp, "X");
strncat(temp, ans, 13);
temp[14] = '\0';
strcpy(ans, temp);
}
beep();
clear_line(win, 12, 24, TRUE);
waddstr(win, "BAD NAME");
wrefresh(win);
return;
}
/*
* Convert a perfectly good Unix file name to fit the CP/M file name
* rules. Used for the modem7 batch file transfer. Returns a pointer
* to a static area containing the new name.
*/
static char *
fix_name(path)
char *path;
{
int i, dot;
char *s, *name, temp[15], *ext, *strncpy(), *strrchr();
static char ans[13];
/* ignore the path component */
if (s = strrchr(path, '/'))
strncpy(temp, ++s, 15);
else
strncpy(temp, path, 15);
temp[14] = '\0';
name = temp;
ext = "";
dot = 0;
for (i=strlen(temp)-1; i>=0; i--) {
if (temp[i] == '.' && !dot) {
dot = 1;
temp[i] = '\0';
ext = &temp[i+1];
}
if (islower(temp[i]))
temp[i] = toupper(temp[i]);
}
/* if null name component */
if (*name == '\0')
name = "X";
/* if name too long */
if (strlen(name) > 8)
*(name+8) = '\0';
/* if extension too long */
if (strlen(ext) > 3)
*(ext+3) = '\0';
sprintf(ans, "%-8.8s%-3.3s%c", temp, ext, CTRLZ);
return(ans);
}
/*
* Convert a CP/M style filename into a legal Unix file name. Loads the
* global character array "file_name".
*/
static void
unfix_name(cpm_name)
char *cpm_name;
{
extern char file_name[15];
register int i, n;
int dot;
char temp[15], *strcpy();
file_name[0] = '\0';
if (*cpm_name == '\0')
return;
strcpy(temp, cpm_name);
/* 8 character of the name */
n = 0;
for (i=0; i<8; i++) {
if (temp[i] != ' ') {
if (isupper(temp[i]))
file_name[n++] = tolower(temp[i]);
else
file_name[n++] = temp[i];
}
}
/* 3 character extension */
dot = 0;
for (i=8; i<11; i++) {
if (temp[i] != ' ') {
if (!dot) {
dot++;
file_name[n++] = '.';
}
if (isupper(temp[i]))
file_name[n++] = tolower(temp[i]);
else
file_name[n++] = temp[i];
}
}
file_name[n] = '\0';
return;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.