diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1999-06-07 10:23:42 +0200 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1999-06-07 10:23:42 +0200 |
commit | 0fceb64d25ff3d9586549bb43d971c5eef904330 (patch) | |
tree | d4799d0fd53a3d8ae342c84f8ad4fb2ca2f14de0 /call/yapp.c |
Import ax25-apps 0.0.1 from tarballax25-apps-0.0.1
Diffstat (limited to 'call/yapp.c')
-rw-r--r-- | call/yapp.c | 840 |
1 files changed, 840 insertions, 0 deletions
diff --git a/call/yapp.c b/call/yapp.c new file mode 100644 index 0000000..3deb6d1 --- /dev/null +++ b/call/yapp.c @@ -0,0 +1,840 @@ +/* yapp.c + * + * Copyright (C) 1994 by Jonathan Naylor + * + * This module implements the YAPP file transfer protocol as defined by Jeff + * Jacobsen WA7MBL in the files yappxfer.doc and yappxfer.pas. + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the license, or (at your option) any later version. + */ + +/* + * Yapp C and Resume support added by S N Henson. + */ + +#include <sys/types.h> +#include <stdio.h> +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <pwd.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <termios.h> +#include <unistd.h> +#include <linux/ax25.h> +#include <sys/stat.h> + +#include "call.h" + +#define TIMEOUT 300 /* 5 Minutes */ + +#define NUL 0x00 +#define SOH 0x01 +#define STX 0x02 +#define ETX 0x03 +#define EOT 0x04 +#define ENQ 0x05 +#define ACK 0x06 +#define DLE 0x10 +#define NAK 0x15 +#define CAN 0x18 + +#define STATE_S 0 +#define STATE_SH 1 +#define STATE_SD 2 +#define STATE_SE 3 +#define STATE_ST 4 +#define STATE_R 5 +#define STATE_RH 6 +#define STATE_RD 7 + +static int state; +static int total = 0; + +static int readlen = 0; +static int outlen = 0; +static int outbufptr = 0; +static unsigned char outbuffer[512]; +static char yappc; /* Nonzero if using YAPP C */ + +static void Write_Status(char *s) +{ + fprintf(stdout, "State: %-60s\r", s); + fflush(stdout); +} + +static void Send_RR(void) +{ + char buffer[2]; + + buffer[0] = ACK; + buffer[1] = 0x01; + + write(fd, buffer, 2); +} + +static void Send_RF(void) +{ + char buffer[2]; + + buffer[0] = ACK; + buffer[1] = 0x02; + + write(fd, buffer, 2); +} + +static void Send_RT(void) +{ + char buffer[2]; + + buffer[0] = ACK; + buffer[1] = ACK; + + write(fd, buffer, 2); +} + +static void Send_AF(void) +{ + char buffer[2]; + + buffer[0] = ACK; + buffer[1] = 0x03; + + write(fd, buffer, 2); +} + +static void Send_AT(void) +{ + char buffer[2]; + + buffer[0] = ACK; + buffer[1] = 0x04; + + write(fd, buffer, 2); +} + +static void Send_NR(char *reason) +{ + char buffer[257]; + int length; + + if ((length = strlen(reason)) > 255) + length = 255; + + buffer[0] = NAK; + buffer[1] = length; + memcpy(buffer + 2, reason, length); + + write(fd, buffer, length + 2); +} + +/* Send a Resume Sequence */ + +static void Send_RS(int length) +{ + char buffer[256]; + int len; + + buffer[0] = NAK; + buffer[2] = 'R'; + buffer[3] = 0; + + len = sprintf(buffer + 4, "%d", length) + 5; + + buffer[len] = 'C'; + buffer[len + 1] = 0; + buffer[1] = len; + + write(fd, buffer, len + 2); +} + +static void Send_SI(void) +{ + char buffer[2]; + + buffer[0] = ENQ; + buffer[1] = 0x01; + + write(fd, buffer, 2); +} + +static void Send_CN(char *reason) +{ + char buffer[257]; + int length; + + if ((length = strlen(reason)) > 255) + length = 255; + + buffer[0] = CAN; + buffer[1] = length; + memcpy(buffer + 2, reason, length); + + write(fd, buffer, length + 2); +} + +static void Send_HD(char *filename, long length) +{ + char buffer[257]; + char size_buffer[10]; + int len_filename; + int len_size; + int len; + struct stat sb; + + sprintf(size_buffer, "%ld", length); + + len_filename = strlen(filename) + 1; /* Include the NUL */ + len_size = strlen(size_buffer) + 1; /* Include the NUL */ + + len = len_filename + len_size; + + if (!stat(filename, &sb)) + { + unix2yapp(sb.st_mtime, buffer + len + 2); + len += 9; + } + + buffer[0] = SOH; + buffer[1] = len; + + memcpy(buffer + 2, filename, len_filename); + memcpy(buffer + len_filename + 2, size_buffer, len_size); + + write(fd, buffer, len + 2); +} + +static void Send_ET(void) +{ + char buffer[2]; + + buffer[0] = EOT; + buffer[1] = 0x01; + + write(fd, buffer, 2); +} + +static void Send_DT(int length) +{ + char buffer[2]; + + if (length > 255) length = 0; + + buffer[0] = STX; + buffer[1] = length; + + write(fd, buffer, 2); +} + +static void Send_EF(void) +{ + char buffer[2]; + + buffer[0] = ETX; + buffer[1] = 0x01; + + write(fd, buffer, 2); +} + +static unsigned char checksum(unsigned char *buf, int len) +{ + int i; + unsigned char sum = 0; + + for (i = 0; i < len; i++) + sum += buf[i]; + + return sum; +} + +static int yapp_download_data(int *filefd, unsigned char *buffer) +{ + int length,file_time; + char Message[50]; + + if (buffer[0] == CAN || buffer[0] == NAK) + { + Write_Status("RcdABORT"); + return(FALSE); + } + + switch (state) + { + case STATE_R: + if (buffer[0] == ENQ && buffer[1] == 0x01) + { + Send_RR(); + Write_Status("RcvHeader"); + state = STATE_RH; + break; + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_RH: + if (buffer[0] == SOH) + { + /* Parse header: 3 fields == YAPP C */ + char *hptr, *hfield[3]; + if ((length = buffer[1]) == 0) length = 256; + hptr = (char *)buffer + 2; + while (length > 0) + { + int hlen; + hlen = strlen(hptr) + 1; + hfield[(int)yappc++] = hptr; + hptr += hlen; + length -= hlen; + } + + if (yappc < 3) + { + yappc = 0; + } + else + { + file_time = yapp2unix(hfield[2]); + yappc = 1; + } + + if (*filefd == -1) + { + if ((*filefd = open(hfield[0], O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) + { + printf("\n[Unable to open %s]\n", hfield[0]); + Send_NR("Invalid filename"); + return(FALSE); + } + } + + printf("Receiving %s %s %s", hfield[0], hfield[1], + yappc ? ctime((time_t *)&file_time) : " "); + + if (yappc) + { + struct stat sb; + + if (!fstat(*filefd, &sb) && sb.st_size) + Send_RS(sb.st_size); + else + Send_RT(); + } + else + { + Send_RF(); + } + + state = STATE_RD; + break; + } + + if (buffer[0] == ENQ && buffer[1] == 0x01) + { + break; + } + + if (buffer[0] == EOT && buffer[1] == 0x01) + { + Send_AT(); + Write_Status("RcvEOT"); + return(FALSE); + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_RD: + if (buffer[0] == STX) + { + if ((length = buffer[1]) == 0) length = 256; + total += length; + sprintf(Message, "RcvData %5d bytes received", total); + Write_Status(Message); + + if (yappc) + { + int i; + unsigned char checksum = 0; + + for (i = 0; i < length; i++) + checksum += buffer[i + 2]; + + if (checksum != buffer[length + 2]) + { + Send_CN("Bad Checksum"); + Write_Status("SndABORT: Bad Checksum"); + return(FALSE); + } + } + + write(*filefd, buffer + 2, length); + break; + } + + if (buffer[0] == ETX && buffer[1] == 0x01) + { + Send_AF(); + Write_Status("RcvEof"); + state = STATE_RH; + close(*filefd); + *filefd = -1; + break; + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + } + + return(TRUE); +} + +static void yapp_download(int filefd) +{ + struct timeval timeval; + fd_set sock_read; + int n; + int buflen = 0; + int length; + int used; + unsigned char buffer[1024]; + + Write_Status("RcvWait"); + + state = STATE_R; + total = 0; + yappc = 0; + + while (TRUE) + { + FD_ZERO(&sock_read); + FD_SET(STDIN_FILENO, &sock_read); + FD_SET(fd, &sock_read); + + timeval.tv_usec = 0; + timeval.tv_sec = TIMEOUT; + + n = select(fd + 1, &sock_read, NULL, NULL, &timeval); + + if (n == -1) + { + if (!interrupted && errno == EAGAIN) + continue; + if (!interrupted) + perror("select"); + Send_CN("Internal error"); + Write_Status("SndABORT"); + return; + } + + if (n == 0) /* Timeout */ + { + Send_CN("Timeout"); + Write_Status("SndABORT"); + return; + } + + if (FD_ISSET(STDIN_FILENO, &sock_read)) + { + Send_CN("Cancelled by user"); + Write_Status("SndABORT"); + return; + } + + if (FD_ISSET(fd, &sock_read)) + { + if ((length = read(fd, buffer + buflen, 511)) > 0) + { + buflen += length; + + do + { + used = FALSE; + + switch (buffer[0]) + { + case ACK: + case ENQ: + case ETX: + case EOT: + if (buflen >= 2) + { + if (!yapp_download_data(&filefd, buffer)) + return; + buflen -= 2; + memcpy(buffer, buffer + 2, buflen); + used = TRUE; + } + break; + default: + if ((length = buffer[1]) == 0) + length = 256; + if (buffer[0] == STX) + length += yappc; + if (buflen >= (length + 2)) + { + if (!yapp_download_data(&filefd, buffer)) + return; + buflen -= length + 2; + memcpy(buffer, buffer + length + 2, buflen); + used = TRUE; + } + break; + } + } + while (used); + } + } + } +} + +static int yapp_upload_data(int filefd, char *filename, int filelength, unsigned char *buffer) +{ + char Message[80]; + + if (buffer[0] == CAN || buffer[0] == NAK) + { + Write_Status("RcvABORT"); + return(FALSE); + } + + switch (state) + { + case STATE_S: + if (buffer[0] == ACK && buffer[1] == 0x01) + { + Write_Status("SendHeader"); + Send_HD(filename, filelength); + state = STATE_SH; + break; + } + + if (buffer[0] == ACK && buffer[1] == 0x02) + { + sprintf(Message, "SendData %5d bytes transmitted", total); + Write_Status(Message); + outlen = read(filefd, outbuffer, readlen); + outbufptr = 0; + + if (outlen) Send_DT(outlen); + + if (yappc) + { + outbuffer[outlen] = checksum(outbuffer, outlen); + outlen++; + } + + state = STATE_SD; + break; + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_SH: + /* Could get three replies here: + * ACK 02 : normal acknowledge. + * ACK ACK: yappc acknowledge. + * NAK ...: resume request. + */ + if (buffer[0] == NAK && buffer[2] == 'R') + { + int len; + off_t rpos; + + len = buffer[1]; + if (buffer[len] == 'C') yappc=1; + rpos = atol((char *)buffer + 4); + lseek(filefd, rpos, SEEK_SET); + buffer[0] = ACK; + buffer[1] = yappc ? ACK : 0x02; + } + + if (buffer[0] == ACK && + (buffer[1] == 0x02 || buffer[1] == ACK)) + { + if (buffer[1] == ACK) yappc = 1; + + sprintf(Message, "SendData %5d bytes transmitted", total); + Write_Status(Message); + outlen = read(filefd, outbuffer, readlen); + outbufptr = 0; + if (outlen) Send_DT(outlen); + state = STATE_SD; + + if (yappc) + { + outbuffer[outlen] = checksum(outbuffer, outlen); + outlen++; + } + break; + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_SD: + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_SE: + if (buffer[0] == ACK && buffer[1] == 0x03) + { + Write_Status("SendEOT"); + Send_ET(); + state = STATE_ST; + break; + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + + case STATE_ST: + if (buffer[0] == ACK && buffer[1] == 0x04) + { + return(FALSE); + } + + Send_CN("Unknown code"); + Write_Status("SndABORT"); + return(FALSE); + } + + return(TRUE); +} + +static void yapp_upload(int filefd, char *filename, long filelength) +{ + struct timeval timeval; + fd_set sock_read; + fd_set sock_write; + int n; + unsigned char buffer[1024]; + int buflen = 0; + int length; + int used; + char Message[80]; + + Write_Status("SendInit"); + + readlen = (paclen - 2 > 253) ? 253 : paclen - 2; + state = STATE_S; + total = 0; + yappc = 0; + + Send_SI(); + + while (TRUE) + { + FD_ZERO(&sock_read); + FD_ZERO(&sock_write); + FD_SET(STDIN_FILENO, &sock_read); + FD_SET(fd, &sock_read); + + if (state == STATE_SD) + { + FD_SET(fd, &sock_write); + + n = select(fd + 1, &sock_read, &sock_write, NULL, NULL); + } + else + { + timeval.tv_usec = 0; + timeval.tv_sec = TIMEOUT; + + n = select(fd + 1, &sock_read, NULL, NULL, &timeval); + } + + if (n == -1) + { + if (!interrupted && errno == EAGAIN) + continue; + if (!interrupted) + perror("select"); + Write_Status("SndABORT"); + Send_CN("Internal error"); + return; + } + + if (n == 0) /* Timeout, not STATE_SD */ + { + Write_Status("SndABORT"); + Send_CN("Timeout"); + return; + } + + if (FD_ISSET(STDIN_FILENO, &sock_read)) + { + Write_Status("SndABORT"); + Send_CN("Cancelled by user"); + return; + } + + if (FD_ISSET(fd, &sock_write)) /* Writable, only STATE_SD */ + { + if (outlen > 0) + { + if ((n = write(fd, outbuffer + outbufptr, outlen)) > 0) + { + outbufptr += n; + outlen -= n; + total += n; + } + } + + if (outlen == 0) + { + total -= yappc; + if ((outlen = read(filefd, outbuffer, readlen)) > 0) + { + sprintf(Message, "SendData %5d bytes transmitted", total); + Write_Status(Message); + + outbufptr = 0; + Send_DT(outlen); + + if (yappc) + { + outbuffer[outlen] = checksum(outbuffer, outlen); + outlen++; + } + } + else + { + Write_Status("SendEof"); + state = STATE_SE; + Send_EF(); + } + } + } + + if (FD_ISSET(fd, &sock_read)) + { + if ((length = read(fd, buffer + buflen, 511)) > 0) + { + buflen += length; + + do + { + used = FALSE; + + switch (buffer[0]) + { + case ACK: + case ENQ: + case ETX: + case EOT: + if (buflen >= 2) + { + if (!yapp_upload_data(filefd, filename, filelength, buffer)) + return; + buflen -= 2; + memcpy(buffer, buffer + 2, buflen); + used = TRUE; + } + break; + default: + if ((length = buffer[1]) == 0) + length = 256; + if (buflen >= (length + 2)) + { + if (!yapp_upload_data(filefd, filename, filelength, buffer)) + return; + buflen -= length + 2; + memcpy(buffer, buffer + length + 2, buflen); + used = TRUE; + } + break; + } + } + while (used); + } + } + } +} + +void cmd_yapp(char *buf, int bytes) +{ + int filefd; + long size = 0L; + char *t; + + if (bytes == 0) return; + + switch (buf[0]) + { + case 'U': + case 'u': + if ((t = strchr(buf, '\n')) != NULL) + *t = '\0'; + t = buf + 2; + while (*t != '\0' && isspace(*t)) + t++; + if (*t == '\0') + { + printf("\n[YAPP Upload requires a filename - eg ~yu hello.txt]\n"); + Send_NR("No filename"); + return; + } + if ((filefd = open(t, O_RDONLY)) == -1) + { + printf("\n[Unable to open upload file]\n"); + Send_NR("Invalid filename"); + return; + } + if (lseek(filefd, 0L, SEEK_END) != -1) + size = lseek(filefd, 0L, SEEK_CUR); + lseek(filefd, 0L, SEEK_SET); + if (size != -1) + printf("\n[Uploading %ld bytes from %s using YAPP]\n", size, t); + else + printf("\n[Uploading from %s using YAPP]\n", t); + yapp_upload(filefd, t, size); + close(filefd); + printf("[Finished YAPP Upload, %d bytes Transmitted]\n", total); + break; + + case 'D': + case 'd': + if ((t = strchr(buf, '\n')) != NULL) + *t = '\0'; + t = buf + 2; + while (*t != '\0' && isspace(*t)) + t++; + if (*t == '\0') filefd=-1; + else if ((filefd = open(t, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) + { + printf("\n[Unable to open %s]\n", buf + 2); + Send_NR("Invalid filename"); + return; + } + printf("\n[Downloading using YAPP]\n"); + yapp_download(filefd); + close(filefd); + printf("[Finished YAPP Download, %d bytes received]\n", total); + break; + + default: + printf("\nUnknown '~y' escape. Type ~h for a list.\n"); + break; + } +} + |