summaryrefslogtreecommitdiffstats
path: root/ax25/axgetput/proto_bin.c
diff options
context:
space:
mode:
authorThomas Osterried <thomas@osterried.de>2006-12-10 19:12:59 +0000
committerThomas Osterried <thomas@osterried.de>2006-12-10 19:12:59 +0000
commitacdb41fa04d40571ee4d84e2607515643d410671 (patch)
treeacf58efd52c6c8360d53f8e57795080089aa4e8f /ax25/axgetput/proto_bin.c
parenta824b0ba5e756660406a8a4648f60692a5cdce30 (diff)
axgetput (bget, bput, ..) for 8bit clean up/download from an
axspawn(8) login session. Initial checkin. Import from http://x-berg.in-berlin.de/cgi-bin/viewcvs.cgi/ampr/axgetput/
Diffstat (limited to 'ax25/axgetput/proto_bin.c')
-rw-r--r--ax25/axgetput/proto_bin.c489
1 files changed, 489 insertions, 0 deletions
diff --git a/ax25/axgetput/proto_bin.c b/ax25/axgetput/proto_bin.c
new file mode 100644
index 0000000..c826ec3
--- /dev/null
+++ b/ax25/axgetput/proto_bin.c
@@ -0,0 +1,489 @@
+/* @(#) $Id: proto_bin.c,v 1.1 2006/12/10 19:12:59 dl9sau Exp $ */
+
+/*
+ * (c) 2002 Thomas Osterried DL9SAU <thomas@x-berg.in-berlin.de>
+ * License: GPL. See http://www.fsf.org/
+ * Sources: http://x-berg.in-berlin.de/cgi-bin/viewcvs.cgi/ampr/axgetput/
+ */
+
+#include "includes.h"
+
+#include "proto_bin.h"
+#include "axgetput.h"
+#include "util.h"
+
+static int crctab[256];
+static int bittab[8] = { 128,64,32,16,8,4,2,1 };
+static int crcbit[8] = {
+ 0x9188,0x48c4,0x2462,0x1231,0x8108,0x4084,0x2042,0x1021
+};
+
+/*---------------------------------------------------------------------------*/
+
+static int init_crc(void)
+{
+ int i,j;
+
+ for (i = 0; i < 256; i++) {
+ crctab[i] = 0;
+ for (j = 0; j < 8; j++) {
+ if ((bittab[j] & i) != 0) {
+ crctab[i] = crctab[i] ^ crcbit[j];
+ }
+ }
+ }
+ return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int do_crc(char b, int n, unsigned int crc)
+{
+ crc = (crctab[(crc >> 8)] ^ ((crc << 8) | (b & 0xff))) & 0xffff;
+ return (crc);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static long parse_sfbin_date_to_unix(const char *s)
+{
+
+ unsigned long x;
+
+ sscanf(s, "%lX", &x);
+
+ return date_dos2unix(((x << 16) >> 16), (x >> 16));
+}
+
+/*---------------------------------------------------------------------------*/
+
+static char * unix_to_sfbin_date_string(long gmt)
+{
+
+ static char buf[9];
+ unsigned short s_time, s_date;
+
+ date_unix2dos(((gmt == -1) ? time(0) : gmt), &s_time, &s_date);
+ sprintf(buf, "%X", ((s_date << 16) + s_time));
+ return buf;
+}
+
+/*---------------------------------------------------------------------------*/
+
+int bput(void)
+{
+ struct stat statbuf;
+ char buf[1024]; /* < signed int */
+ char tmpbuf[1024];
+ char filename_given[PATH_MAX];
+ unsigned long len_read_expected = 0;
+ unsigned long len_read_left;
+ time_t file_time = 0L;
+ unsigned int msg_crc = 0;
+ unsigned int crc = 0;
+ char *term_line = 0;
+ int last_line_had_CR = 0;
+ int len_termline = 0;
+ int len = 0;
+ int fddata = fdout;
+ int is_eof;
+ char *p, *q;
+
+#define save_close(x) { \
+ if (!fdout_is_pipe) \
+ close(x); \
+}
+
+
+ for (;;) {
+ len = my_read(fdin, buf, sizeof(buf), &is_eof, "\r\n");
+ if (is_eof || len < 1) {
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ return 1;
+ }
+ if (buf[len-1] == '\n') {
+ //p = "warning: <LF> received. not 8bit clean?\r";
+ //secure_write(fdout, p, strlen(p));
+ sprintf(err_msg, "bad EOL: <LF>\n");
+ return 1;
+ }
+ if (IS_BIN_ABORT(buf, len)) {
+ sprintf(err_msg, "Aborted by user request\n");
+ return 1;
+ }
+ if (buf[len-1] == '\r' && len > 5 && !memcmp(buf, "#BIN#", 5)) {
+ break;
+ }
+ if (len == sizeof(buf)) {
+ sprintf(err_msg, "line to long\n");
+ return 1;
+ }
+ }
+ buf[len-1] = 0; // without trailing \r. and: string termination
+
+ send_on_signal = bin_send_no_on_sig;
+
+ /* parse #BIN arguments */
+ *filename_given = 0;
+ *tmpbuf = 0;
+ sscanf(buf, "#BIN#%ld#|%d#%s", &len_read_expected, &msg_crc, tmpbuf);
+ p = tmpbuf;
+ if (*tmpbuf == '$') {
+ p++;
+ if ((q = strchr(tmpbuf, '#'))) {
+ *q++ = 0;
+ p = q;
+ }
+ file_time = parse_sfbin_date_to_unix(tmpbuf+1);
+ }
+ strncpy(filename_given, p, sizeof(filename_given)-1);
+ filename_given[sizeof(filename_given)-1] = 0;
+
+ if (!fdout_is_pipe) {
+ // normal mode: store in given filename
+ if (!*filename) {
+ p = get_fixed_filename(filename_given, len_read_expected, msg_crc, 1);
+ strncpy(filename, p, sizeof(filename)-1);
+ filename[sizeof(filename)-1] = 0;
+ }
+ if (!stat(filename, &statbuf)) {
+ // file exist
+ if (unlink(filename)) {
+ sprintf(err_msg, "error: cannot unlink %s (%s)\n", filename, strerror(errno));
+ goto abort;
+ }
+ }
+ if ((fddata = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0640)) < 0) {
+ sprintf(err_msg, "error: cannot open %s (%s)\n", filename, strerror(errno));
+ write(fderr, "\r#NO#\r", 6);
+ return 1;
+ }
+ }
+
+ if (!len_read_expected) {
+ term_line = "***END\r";
+ len_termline = strlen(term_line);
+ }
+
+ // say helo
+ send_on_signal = bin_send_abort_on_sig;
+ write(fderr, "\r#OK#\r", 6);
+
+ len_read_left = len_read_expected;
+
+ // #bin# chechsum initialization
+ init_crc();
+
+ for (;;) {
+
+ if ((len = my_read(fdin, buf, ((term_line || len_read_left > sizeof(buf)) ? sizeof(buf) : len_read_left), &is_eof, "\r")) < 1) {
+ save_close(fddata);
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ goto abort;
+ }
+ if (!len) {
+ save_close(fddata);
+ if (!term_line) {
+ sprintf(err_msg, "error: unexpected end of file during read: %s\n", strerror(errno));
+ return 1;
+ }
+ return 0;
+ }
+
+ if (msg_crc) {
+ int i;
+ for (i = 0; i < len; i++)
+ crc = do_crc((int ) buf[i], 1, crc);
+ }
+
+ if (buf[len-1] == '\r') {
+ if (last_line_had_CR) {
+ if (IS_BIN_ABORT(buf, len)) {
+ // "\r#ABORT#\r" was sent
+ if (!fdout_is_pipe) {
+ close(fddata);
+ // clean up
+ unlink(filename);
+ }
+ return 1;
+ }
+ if (term_line && len == len_termline && !memcmp(buf, term_line, len_termline)) {
+ // sucessfully read until termination string
+ break;
+ }
+ }
+ last_line_had_CR = 1;
+ } else {
+ last_line_had_CR = 0;
+ }
+ if (!term_line)
+ len_read_left -= len;
+
+ if (secure_write(fddata, buf, len) == -1) {
+ save_close(fddata);
+ sprintf(err_msg, "error: write failed (%s)\n", strerror(errno));
+ goto abort;
+ }
+
+ // nothing left?
+ if (!term_line && len_read_left == 0L)
+ break;
+ if (is_eof) {
+ if (!term_line && len_read_left) {
+ save_close(fddata);
+ goto abort;
+ }
+ break;
+ }
+ }
+ if (crc != msg_crc) {
+ sprintf(err_msg, "Invalid crc: computed %d, expected %d.\n", crc, msg_crc);
+ // don't unlink
+ save_close(fddata);
+ return 1;
+ }
+ if (!fdout_is_pipe) {
+ close(fddata);
+ if (file_time != 0L) {
+ struct utimbuf utb;
+ utb.modtime = file_time;
+ utb.actime = time(0);
+ utime(filename, &utb);
+ }
+ }
+
+ send_on_signal = 0;
+ return 0;
+
+abort:
+ sleep(1);
+ write(fderr, "\r#ABORT#\r", 9);
+ return 1;
+#undef save_close
+}
+
+/*---------------------------------------------------------------------------*/
+
+int bget(void) {
+ struct strlist {
+ struct strlist *next;
+ size_t len;
+ char data[1]; /* actually a the address of char * pointer */
+ };
+
+ struct strlist *stored_file = 0;
+ struct strlist *sl_tail = 0;
+ struct strlist *sl;
+ struct timeval timeout;
+ struct stat statbuf;
+
+ unsigned int crc = 0;
+
+ char buf[1024];
+ fd_set readfds;
+ int fddata = fdin;
+ int len;
+ unsigned long file_size = 0;
+ unsigned long len_remains;
+ int is_eof;
+ int file_time = 0L;
+
+#define save_close(x) { \
+ if (!fdin_is_pipe) \
+ close(x); \
+}
+
+#define store_line(s, len) { \
+ if (!(sl = (struct strlist *) malloc(sizeof(struct strlist *) + sizeof(size_t) + len))) \
+ return 1; \
+ sl->next = 0; \
+ sl->len = len; \
+ memcpy(sl->data, s, len); \
+ if (!stored_file) { \
+ stored_file = sl; \
+ } else { \
+ sl_tail->next = sl; \
+ } \
+ sl_tail = sl; \
+}
+
+ if (BLOCKSIZ < 1 || BLOCKSIZ > sizeof(buf))
+ BLOCKSIZ = BLOCKSIZ_DEFAULT;
+
+ init_crc();
+
+ if (!fdin_is_pipe && *filename) {
+ if ((fddata = open(filename, O_RDONLY)) == -1) {
+ sprintf(err_msg, "error: cannot open %s (%s)\n", filename, strerror(errno));
+ return 1;
+ }
+ if (!fstat(fddata, &statbuf))
+ file_time = statbuf.st_mtime;
+ else
+ file_time = time(0);
+
+ // compute crc
+ while ((len = read(fddata, buf, BLOCKSIZ)) > 0) {
+ int i;
+ for (i = 0; i < len; i++)
+ crc = do_crc((int ) buf[i], 1, crc);
+ file_size += len;
+ }
+ if (len < 0) {
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ close(fddata);
+ return 1;
+ }
+ // rewind
+ if (lseek(fddata, 0L, SEEK_SET) != 0L) {
+ sprintf(err_msg, "error: file io failed on lseek() (%s)\n", strerror(errno));
+ close(fddata);
+ return 1;
+ }
+ sprintf(buf, "\r#BIN#%ld#|%d#$%s#%s\r", file_size, crc, unix_to_sfbin_date_string(file_time), get_fixed_filename(filename, file_size, crc, 1));
+ } else {
+ file_time = time(0);
+ if (!is_stream || do_crc_only) {
+ sprintf(err_msg, "error: not enough memory\n");
+ while ((len = read(fddata, buf, sizeof(buf))) > 0) {
+ int i;
+ for (i = 0; i < len; i++)
+ crc = do_crc((int ) buf[i], 1, crc);
+ file_size += len;
+ if (!do_crc_only)
+ store_line(buf, len);
+ }
+ if (len < 0) {
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ close(fddata);
+ return 1;
+ }
+ *err_msg = 0;
+ sprintf(buf, "\r#BIN#%ld#|%d#$%s#%s\r", file_size, crc, unix_to_sfbin_date_string(file_time), get_fixed_filename(filename, file_size, crc, 1));
+ } else {
+ sprintf(buf, "\r#BIN###$%s#%s\r", unix_to_sfbin_date_string(file_time), get_fixed_filename(filename, 0, 0, 1));
+ }
+ // hack: check for #ABORT# from fdout (fd 1), because fddata (fd 0) is
+ // our pipe we read the data from, which we actually tx.
+ // believe me, it does work.
+ fdin = fdout;
+ }
+
+ if (do_crc_only) {
+ printf("File information for %s:\n", get_fixed_filename(filename, file_size, crc, 1));
+ printf(" size %ld bytes, crc %d, date %s (%d)\n", file_size, crc, unix_to_sfbin_date_string(file_time), file_time);
+ return 0;
+ }
+
+ send_on_signal = bin_send_abort_on_sig;
+ if (secure_write(fdout, buf, strlen(buf)) == -1) {
+ sprintf(err_msg, "error: write failed (%s)\n", strerror(errno));
+ save_close(fddata);
+ return 1;
+ }
+
+ // wait for answer
+ for (;;) {
+ // . make sure we do not read from a pipe. fdout is also
+ // | assigned to the tty
+ len = my_read(fdout, buf, sizeof(buf), &is_eof, "\r\n");
+ if (is_eof || len < 1) {
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ save_close(fddata);
+ return 1;
+ }
+ if (buf[len-1] == '\n') {
+ //char *p = "warning: <LF> received. not 8bit clean?\r";
+ //secure_write(fdout, p, strlen(p));
+ sprintf(err_msg, "bad EOL: <LF>\n");
+ goto abort;
+ } else if (buf[len-1] != '\r') {
+ sprintf(err_msg, "line to long\n");
+ continue;
+ }
+ if (IS_BIN_OK(buf, len))
+ break;
+ if (IS_BIN_NO(buf, len)) {
+ save_close(fddata);
+ return 0;
+ }
+ if (IS_BIN_ABORT(buf, len)) {
+ sprintf(err_msg, "Aborted by user request\n");
+ save_close(fddata);
+ return 1;
+ }
+ }
+
+ len_remains = file_size;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+
+ for (;;) {
+ char *p_buf;
+
+ // check for user \r#ABORT#\r on tty stream
+ FD_ZERO(&readfds);
+ FD_SET(fdin, &readfds);
+ if (select(fdin+1, &readfds, 0, 0, &timeout) && FD_ISSET(fdin, &readfds)) {
+ if ((len = read(fdin, buf, sizeof(buf))) < 0) {
+ sprintf(err_msg, "read from tty failed (%s)\n", strerror(errno));
+ save_close(fddata);
+ goto abort;
+ }
+ if (IS_BIN_ABORT(buf, len)) {
+ sprintf(err_msg, "Aborted by user request\n");
+ save_close(fddata);
+ return 1;
+ }
+ }
+ // read data
+ if (!fdin_is_pipe || is_stream) {
+ p_buf = buf;
+ if ((len = my_read(fddata, buf, ((len_remains > BLOCKSIZ || is_stream) ? BLOCKSIZ : len_remains), &is_eof, 0)) < 1) {
+ save_close(fddata);
+ if (len < 0) {
+ sprintf(err_msg, "error: read failed (%s)\n", strerror(errno));
+ goto abort;
+ }
+ break;
+ }
+ len_remains -= len;
+ } else {
+ p_buf = stored_file->data;
+ len = stored_file->len;
+ }
+ // write to client
+ if (secure_write(fdout, p_buf, len) == -1) {
+ sprintf(err_msg, "error: write failed (%s)\n", strerror(errno));
+ save_close(fddata);
+ goto abort;
+ }
+ if (fdin_is_pipe && !is_stream) {
+ sl = stored_file;
+ if (!(stored_file = stored_file->next))
+ is_eof = 1;
+ free(sl);
+ }
+ if (!fdin_is_pipe && !len_remains) {
+ if (read(fddata, buf, 1) == 1) {
+ sprintf(err_msg, "Warning: file has grown in the meantime\n");
+ }
+ is_eof = 1;
+ break;
+ }
+ // need this because my_read may returned lenth != 0 (data to be written)
+ // but also has detected EOF.
+ if (is_eof)
+ break;
+ }
+
+ sleep(10);
+
+ return 0;
+
+abort:
+ sleep(1);
+ write(fderr, "\r#ABORT#\r", 9);
+ return 1;
+#undef save_close
+}