From 0fceb64d25ff3d9586549bb43d971c5eef904330 Mon Sep 17 00:00:00 2001 From: Ralf Baechle Date: Mon, 7 Jun 1999 10:23:42 +0200 Subject: Import ax25-apps 0.0.1 from tarball --- call/Makefile.am | 25 + call/Makefile.in | 370 +++++++++++ call/call.1 | 178 +++++ call/call.c | 1941 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ call/call.h | 20 + call/crc.c | 38 ++ call/crc.h | 2 + call/dostime.c | 85 +++ call/menu.c | 335 ++++++++++ call/menu.h | 27 + call/yapp.c | 840 +++++++++++++++++++++++ 11 files changed, 3861 insertions(+) create mode 100644 call/Makefile.am create mode 100644 call/Makefile.in create mode 100644 call/call.1 create mode 100644 call/call.c create mode 100644 call/call.h create mode 100644 call/crc.c create mode 100644 call/crc.h create mode 100644 call/dostime.c create mode 100644 call/menu.c create mode 100644 call/menu.h create mode 100644 call/yapp.c (limited to 'call') diff --git a/call/Makefile.am b/call/Makefile.am new file mode 100644 index 0000000..9668863 --- /dev/null +++ b/call/Makefile.am @@ -0,0 +1,25 @@ + +vardir = $(sysconfdir)/ax25 + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + + +bin_PROGRAMS = call + +man_MANS = call.1 + +EXTRA_DIST = $(man_MANS) + +call_LDADD = $(NCURSES_LIB) $(AX25_LIB) + +call_SOURCES = \ + call.c \ + call.h \ + menu.c \ + menu.h \ + crc.c \ + crc.h \ + yapp.c \ + dostime.c + diff --git a/call/Makefile.in b/call/Makefile.in new file mode 100644 index 0000000..2f76982 --- /dev/null +++ b/call/Makefile.in @@ -0,0 +1,370 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +AWK = @AWK@ +AX25_LIB = @AX25_LIB@ +CC = @CC@ +DLLTOOL = @DLLTOOL@ +LD = @LD@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAKEINFO = @MAKEINFO@ +NCURSES_LIB = @NCURSES_LIB@ +NM = @NM@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ + +vardir = $(sysconfdir)/ax25 + +bin_PROGRAMS = call + +man_MANS = call.1 + +EXTRA_DIST = $(man_MANS) + +call_LDADD = $(NCURSES_LIB) $(AX25_LIB) + +call_SOURCES = call.c call.h menu.c menu.h crc.c crc.h yapp.c dostime.c + +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +PROGRAMS = $(bin_PROGRAMS) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +call_OBJECTS = call.o menu.o crc.o yapp.o dostime.o +call_DEPENDENCIES = +call_LDFLAGS = +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +man1dir = $(mandir)/man1 +MANS = $(man_MANS) + +NROFF = nroff +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = tar +GZIP_ENV = --best +SOURCES = $(call_SOURCES) +OBJECTS = $(call_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .s +$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps call/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-binPROGRAMS: + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +distclean-binPROGRAMS: + +maintainer-clean-binPROGRAMS: + +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(bindir) + @list='$(bin_PROGRAMS)'; for p in $$list; do \ + if test -f $$p; then \ + echo " $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`"; \ + $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + else :; fi; \ + done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + list='$(bin_PROGRAMS)'; for p in $$list; do \ + rm -f $(DESTDIR)$(bindir)/`echo $$p|sed 's/$(EXEEXT)$$//'|sed '$(transform)'|sed 's/$$/$(EXEEXT)/'`; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +call: $(call_OBJECTS) $(call_DEPENDENCIES) + @rm -f call + $(LINK) $(call_LDFLAGS) $(call_OBJECTS) $(call_LDADD) $(LIBS) + +install-man1: + $(mkinstalldirs) $(DESTDIR)$(man1dir) + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \ + else file=$$i; fi; \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \ + $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \ + done + +uninstall-man1: + @list='$(man1_MANS)'; \ + l2='$(man_MANS)'; for i in $$l2; do \ + case "$$i" in \ + *.1*) list="$$list $$i" ;; \ + esac; \ + done; \ + for i in $$list; do \ + ext=`echo $$i | sed -e 's/^.*\\.//'`; \ + inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \ + inst=`echo $$inst | sed '$(transform)'`.$$ext; \ + echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \ + rm -f $(DESTDIR)$(man1dir)/$$inst; \ + done +install-man: $(MANS) + @$(NORMAL_INSTALL) + $(MAKE) $(AM_MAKEFLAGS) install-man1 +uninstall-man: + @$(NORMAL_UNINSTALL) + $(MAKE) $(AM_MAKEFLAGS) uninstall-man1 + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = call + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done +call.o: call.c ../config.h ../pathnames.h call.h crc.h menu.h +crc.o: crc.c +dostime.o: dostime.c +menu.o: menu.c menu.h +yapp.o: yapp.c call.h + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: install-binPROGRAMS +install-exec: install-exec-am + +install-data-am: install-man +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-binPROGRAMS uninstall-man +uninstall: uninstall-am +all-am: Makefile $(PROGRAMS) $(MANS) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(mandir)/man1 + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-binPROGRAMS mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-binPROGRAMS clean-compile clean-libtool clean-tags \ + clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-binPROGRAMS distclean-compile distclean-libtool \ + distclean-tags distclean-generic clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-binPROGRAMS \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-binPROGRAMS distclean-binPROGRAMS clean-binPROGRAMS \ +maintainer-clean-binPROGRAMS uninstall-binPROGRAMS install-binPROGRAMS \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-libtool distclean-libtool \ +clean-libtool maintainer-clean-libtool install-man1 uninstall-man1 \ +install-man uninstall-man tags mostlyclean-tags distclean-tags \ +clean-tags maintainer-clean-tags distdir info-am info dvi-am dvi check \ +check-am installcheck-am installcheck install-exec-am install-exec \ +install-data-am install-data install-am install uninstall-am uninstall \ +all-redirect all-am all installdirs mostlyclean-generic \ +distclean-generic clean-generic maintainer-clean-generic clean \ +mostlyclean distclean maintainer-clean + + +installconf: + $(mkinstalldirs) $(DESTDIR)$(etcdir) + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/call/call.1 b/call/call.1 new file mode 100644 index 0000000..25b8c65 --- /dev/null +++ b/call/call.1 @@ -0,0 +1,178 @@ +.TH CALL 1 "27 August 1996" Linux "Linux Programmer's Manual" +.SH NAME +call \- make an AX.25, NET/ROM or Rose connection. +.SH SYNOPSIS +For AX.25 +.br +.B call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-t] [-v] [-w window] port callsign [[via] digipeaters.....] +.sp 1 +For NET/ROM +.br +.B call [-d] [-h] [-p paclen] [-r] [-t] [-v] port callsign +.sp 1 +For Rose +.br +.B call [-d] [-h] [-r] [-t] [-v] port callsign address [[via] digipeater] +.br +.SH DESCRIPTION +.LP +.B Call +is the general purpose AX.25, NET/ROM and Rose connection program. As is normal +in AX.25 it runs entirely in line mode. All CR/LF translation is done +transparently. The program provides ASCII, YAPP, YAPP-C and 7+ file +transfer facilities. Some of the options are only valid in AX.25 mode, +the program will quietly ignore them if given in NET/ROM mode or in Rose +mode. +.LP +This version of +.B call +incorporates many changes that include a much improved user interface. The +port name is mandatory and is the name of the port which the connection will +be made on. The port name may be either an AX.25, a NET/ROM port or a Rose +port, +.B call +will determine which automatically. +.LP +When using NET/ROM the use of digipeaters is meaningless and is not +supported. However when using Rose up to one digipeater may be specified, as +well as the Rose address of the distant node and the callsign of the remote +station. The Rose address must be ten digits long and it must exist in the +Rose node tables. For Rose connects to work +.B axparms +must have been used to set a callsign/uid mapping for the userid in use. +.SH OPTIONS +.TP 10 +.BI "\-b l|e" +Sets the method of backoff to use with AX.25 connections. The default is +taken from the port specification, but can be overridden by this option. +Valid values are +.B l +for linear backoff, and +.B e +for exponential backoff. +.TP 10 +.BI \-d +Turn on socket level debugging. +.TP 10 +.BI \-h +Selects Slave mode. +.TP 10 +.BI "\-m s|e" +Sets the AX.25 mode to use. The default is taken from the port +specification, but can be overridden by this option. Valid values are +.B s +for normal (modulus 8) AX.25 operation, or +.B e +for extended (modulus 128) AX.25 operation. +.TP 10 +.BI "\-p paclen" +Specify a specific maximum amount of data to be sent in each AX.25 packet. +.TP 10 +.BI \-r +Selects Raw mode. +.TP 10 +.BI \-t +Selects Talk mode. +.TP 10 +.BI \-v +Display the version. +.TP 10 +.BI "\-w window" +Specify a specific AX.25 window for this connection. Only valid in AX.25 mode. +.LP +The call program interprets lines beginning with a '~' specially. +The following '~' escapes are available. +.TP 16 +.BI ~? +List escapes +.TP 16 +.BI ~~ +A ~ symbol +.TP 16 +.BI ~. +Close connection +.TP 16 +.BI "~! [command]" +Run a command +.TP 16 +.BI ~0 +Change to Raw mode +.TP 16 +.BI ~1 +Change to Slave mode +.TP 16 +.BI ~2 +Change to Talk mode +.TP 16 +.BI ~a +Start a file transfer (Autobin) +.TP 16 +.BI ~b +Start a file transfer (Binary) +.TP 16 +.BI ~c +Close the logfile +.TP 16 +.BI ~h +List escapes +.TP 16 +.BI "~o [filename]" +Open a logfile (default 'logfile.txt') +.TP 16 +.BI ~r +Reconnect to remote station +.TP 16 +.BI ~s +Stop an upload +.TP 16 +.BI "~u [filename]" +Upload a file (ASCII upload) +.TP 16 +.BI "~yu [filename]" +Upload a file (YAPP upload) +.TP 16 +.BI "~yd [filename]" +Download a file (YAPP download) +.TP 16 +.BI ~z +Suspend program +.LP +The program provides no terminal emulation features. These are left +up to the console facilities of the terminal in use. The program is +however '8 bit clean'. +.SH FILES +.nf +/proc/net/nr_nodes +.br +/proc/net/rose_nodes +.br +/etc/ax25/axports +.br +/etc/ax25/nrports +.br +/etc/ax25/rsports +.fi +.SH "SEE ALSO" +.BR listen (1), +.BR mheard (1), +.BR ax25 (4), +.BR netrom (4), +.BR rose (4), +.BR axports (5), +.BR nrports (5), +.BR rsports (5), +.BR axparms (8), +.BR nrparms (8), +.BR rsparms (8). +.SH AUTHORS +.nf +Alexander Tietzel DG6XA +.br +Joerg Reuter DL1BKE +.br +Alan Cox GW4PTS +.br +Jonathan Naylor G4KLX +.br +Steve Henson G6IXS +.fi diff --git a/call/call.c b/call/call.c new file mode 100644 index 0000000..aed1aa5 --- /dev/null +++ b/call/call.c @@ -0,0 +1,1941 @@ +/* 03.04.1995 add binary download "#BIN#-Protocol" Alexander Tietzel */ +/* 01.05.1995 talkmode Alexander Tietzel (DG6XA) */ +/* 15.07.1995 Pull-Down-Menus Alexander Tietzel (DG6XA) */ +/* 17.07.1995 auto7+ newer #BIN#-Protocol Alexander Tietzel(DG6XA) */ +/* 18.07.1995 Remote commands Alexander Tietzel (DG6XA) */ +/* 19.07.1995 statusline Alexander Tietzel (DG6XA) */ +/* 25.07.1995 some bug-fixes Alexander Tietzel (DG6XA) */ +/* 14.08.1995 merged with mainstream call.c code Jonathan Naylor (G4KLX) */ +/* 01.03.1996 support for different screen sizes, fixed 7plus download (DL1BKE) + */ +/* 19.08.1996 fixed enter key handling (G4KLX) */ +/* 27.08.1996 added Rose support (G4KLX) */ +/* 30.11.1996 added the called user in the call windows and set talk mode as + default (IW0FBB) */ +/* 07.12.1996 updated status line to cope with callsign, bits and status + message (VK2KTJ) */ +/* 02.02.1997 removed NETROM_PACLEN setting to match Jonathon removing it + from kernel (VK2KTJ) */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "../pathnames.h" + +#include "call.h" +#include "crc.h" +#include "menu.h" + +#define CTRL_C 0x03 + +#define MAX_PACKETLEN 512 +#define MAX_BUFLEN 2*MAX_PACKETLEN +#define MAX_CMPSTRLEN MAX_PACKETLEN + +#define STD_DWN_DIR "/var/spool/ax25/" + +#define FLAG_RECONNECT 0x01 + +#define STATW_BITS 12 +#define STATW_STAT 20 + +static int backoff = -1; +static int ax25mode = -1; + +static int debug = FALSE; +static int af_mode = AF_AX25; +static int window = 0; +static char *port = NULL; + +int interrupted = FALSE; +int paclen = 0; +int fd; + +typedef struct { + char file_name[255]; + long dwn_cnt; + int dwn_file; + int file_crc; + int calc_crc; + struct utimbuf ut; + int new_header; +} t_gp; + +typedef struct { + WINDOW *ptr; + int max_y; + int max_x; + char string[MAX_BUFLEN]; + int bytes; + int curs_pos; +} t_win; + +#define TALKMODE 001 /* two windows (outgoing and incoming) with menu */ +#define SLAVEMODE 002 /* Menu mode */ +#define RAWMODE 004 /* mode used by earlier versions */ + +WINDOW *win; +const char *key_words[] = +{"//", + "#BIN#", + " go_7+. ", + " stop_7+. ", + "\0" +}; +#define MAXCMDLEN 10 + +void convert_cr_lf(char *buf, int len) +{ + while (len--) { + if (*buf == '\r') + *buf = '\n'; + buf++; + } +} + +void convert_lf_cr(char *buf, int len) +{ + while (len--) { + if (*buf == '\n') + *buf = '\r'; + buf++; + } +} + +void convert_upper_lower(char *buf, int len) +{ + while (len--) { + *buf = tolower(*buf); + buf++; + } +} + +static int nr_convert_call(char *address, struct full_sockaddr_ax25 *addr) +{ + char buffer[100], *call, *alias; + FILE *fp; + int addrlen; + + for (call = address; *call != '\0'; call++) + *call = toupper(*call); + + if ((fp = fopen(PROC_NR_NODES_FILE, "r")) == NULL) { + fprintf(stderr, "call: NET/ROM not included in the kernel\n"); + return -1; + } + fgets(buffer, 100, fp); + + while (fgets(buffer, 100, fp) != NULL) { + call = strtok(buffer, " \t\n\r"); + alias = strtok(NULL, " \t\n\r"); + + if (strcmp(address, call) == 0 || strcmp(address, alias) == 0) { + addrlen = ax25_aton(call, addr); + fclose(fp); + return (addrlen == -1) ? -1 : sizeof(struct sockaddr_ax25); + } + } + + fclose(fp); + + fprintf(stderr, "call: NET/ROM callsign or alias not found\n"); + + return -1; +} + +static int connect_to(char *address[]) +{ + int fd = 0; + int addrlen = 0; + union { + struct full_sockaddr_ax25 ax25; + struct sockaddr_rose rose; + } sockaddr; + char *digi; + int one = debug; + + switch (af_mode) { + case AF_ROSE: + if (address[0] == NULL || address[1] == NULL) { + fprintf(stderr, "call: too few arguments for Rose\n"); + return (-1); + } + if ((fd = socket(AF_ROSE, SOCK_SEQPACKET, 0)) < 0) { + perror("socket"); + return (-1); + } + break; + + case AF_NETROM: + if (address[0] == NULL) { + fprintf(stderr, "call: too few arguments for NET/ROM\n"); + return (-1); + } + if ((fd = socket(AF_NETROM, SOCK_SEQPACKET, 0)) < 0) { + perror("socket"); + return (-1); + } + ax25_aton(nr_config_get_addr(port), &sockaddr.ax25); + sockaddr.ax25.fsa_ax25.sax25_family = AF_NETROM; + addrlen = sizeof(struct full_sockaddr_ax25); + break; + + case AF_AX25: + if (address[0] == NULL) { + fprintf(stderr, "call: too few arguments for AX.25\n"); + return (-1); + } + if ((fd = socket(AF_AX25, SOCK_SEQPACKET, 0)) < 0) { + perror("socket"); + return (-1); + } + ax25_aton(ax25_config_get_addr(port), &sockaddr.ax25); + sockaddr.ax25.fsa_ax25.sax25_family = AF_AX25; + addrlen = sizeof(struct full_sockaddr_ax25); + + if (setsockopt(fd, SOL_AX25, AX25_WINDOW, &window, sizeof(window)) == -1) { + perror("AX25_WINDOW"); + close(fd); + return (-1); + } + if (setsockopt(fd, SOL_AX25, AX25_PACLEN, &paclen, sizeof(paclen)) == -1) { + perror("AX25_PACLEN"); + close(fd); + return (-1); + } + if (backoff != -1) { + if (setsockopt(fd, SOL_AX25, AX25_BACKOFF, &backoff, sizeof(backoff)) == -1) { + perror("AX25_BACKOFF"); + close(fd); + return (-1); + } + } + if (ax25mode != -1) { + if (setsockopt(fd, SOL_AX25, AX25_EXTSEQ, &ax25mode, sizeof(ax25mode)) == -1) { + perror("AX25_EXTSEQ"); + close(fd); + return (-1); + } + } + break; + } + + if (debug && setsockopt(fd, SOL_SOCKET, SO_DEBUG, &one, sizeof(one)) == -1) { + perror("SO_DEBUG"); + close(fd); + return (-1); + } + if (af_mode != AF_ROSE) { /* Let Rose autobind */ + if (bind(fd, (struct sockaddr *) &sockaddr, addrlen) == -1) { + perror("bind"); + close(fd); + return (-1); + } + } + switch (af_mode) { + case AF_ROSE: + memset(&sockaddr.rose, 0x00, sizeof(struct sockaddr_rose)); + + if (ax25_aton_entry(address[0], sockaddr.rose.srose_call.ax25_call) == -1) { + close(fd); + return (-1); + } + if (rose_aton(address[1], sockaddr.rose.srose_addr.rose_addr) == -1) { + close(fd); + return (-1); + } + if (address[2] != NULL) { + digi = address[2]; + if (strcasecmp(address[2], "VIA") == 0) { + if (address[3] == NULL) { + fprintf(stderr, "call: callsign must follow 'via'\n"); + close(fd); + return (-1); + } + digi = address[3]; + } + if (ax25_aton_entry(digi, sockaddr.rose.srose_digi.ax25_call) == -1) { + close(fd); + return (-1); + } + sockaddr.rose.srose_ndigis = 1; + } + sockaddr.rose.srose_family = AF_ROSE; + addrlen = sizeof(struct sockaddr_rose); + break; + + case AF_NETROM: + if (nr_convert_call(address[0], &sockaddr.ax25) == -1) { + close(fd); + return (-1); + } + sockaddr.rose.srose_family = AF_NETROM; + addrlen = sizeof(struct sockaddr_ax25); + break; + + case AF_AX25: + if (ax25_aton_arglist(address, &sockaddr.ax25) == -1) { + close(fd); + return (-1); + } + sockaddr.rose.srose_family = AF_AX25; + addrlen = sizeof(struct full_sockaddr_ax25); + break; + } + + printf("Trying...\r"); + fflush(stdout); + + if (connect(fd, (struct sockaddr *) &sockaddr, addrlen)) { + printf("\n"); + perror("connect"); + close(fd); + return (-1); + } + printf("*** Connected to %s\n", address[0]); + + return (fd); +} + +void cmd_intr(int sig) +{ + signal(SIGQUIT, cmd_intr); + interrupted = TRUE; +} + +void statline(int mode, char *s) +{ + static int oldlen = 0; + int l, cnt; + + if (*s == '\0') { + if (mode == RAWMODE) + return; + if (oldlen > 0) { + move(0, STATW_STAT); + attron(A_REVERSE); + for (cnt = 0; cnt < oldlen; cnt++) + addch(' '); + oldlen = 0; + attroff(A_REVERSE); + refresh(); + } + return; + } + if (mode == RAWMODE) { + printf(">>%s\n", s); + return; + } + if (strlen(s) > 80 - STATW_STAT) + s[80 - STATW_STAT] = '\0'; + + move(0, STATW_STAT); + + attron(A_REVERSE); + addstr(s); + + if (oldlen > strlen(s)) { + l = oldlen - strlen(s); + for (cnt = 0; cnt < l; cnt++) + addch(' '); + } + attroff(A_REVERSE); + oldlen = strlen(s); + refresh(); +} + +WINDOW * + opnstatw(int mode, wint * wintab, char *s, int lines, int cols) +{ + WINDOW *win; + + if (mode == RAWMODE) { + printf(">>%s\n", s); + return NULL; + } + win = winopen(wintab, lines, cols, ((LINES - 1) - lines) / 2, ((COLS) - cols) / 2, TRUE); + mvwaddstr(win, 1, 1 + (cols - strlen(s)) / 2, s); + wmove(win, 3, 2); + + return win; +} + +void wrdstatw(WINDOW * win, char s[]) +{ + int y, x; + + if (win == NULL) { + printf(" %s\n", s); + return; + } + waddstr(win, s); + getyx(win, y, x); + wmove(win, y + 1, 2); + wrefresh(win); +} + +void dupdstatw(WINDOW * win, char *s, int add) +{ + static char infostr[80]; + static int y, x; + static oldlen; + int l, cnt; + + if (add) { + oldlen = 0; + strcpy(infostr, s); + + if (win == NULL) { + printf(" %s", s); + return; + } + waddstr(win, s); + getyx(win, y, x); + wrefresh(win); + + return; + } + if (win == NULL) { + printf("\r %s%s", infostr, s); + } else { + mvwaddstr(win, y, x, s); + } + + if (oldlen > strlen(s)) { + l = oldlen - strlen(s); + for (cnt = 0; cnt < l; cnt++) + if (win == NULL) + printf(" "); + else + waddch(win, ' '); + } + if (win == NULL) { + fflush(stdout); + } else { + wrefresh(win); + } + + oldlen = strlen(s); +} + +int start_ab_download(int mode, WINDOW ** swin, wint * wintab, char parms[], int parmsbytes, char buf[], int bytes, t_gp * gp, char *address[]) +{ + int crcst; /* startposition crc-field */ + int datest = 0; /* startposition date-field */ + int namest = 0; /* startposition name-field */ + int cnt; + int date = 0; + struct tm ft; + char s[80]; + + for (crcst = 2; (!(parms[crcst - 2] == '#' + && parms[crcst - 1] == '|') + && crcst < parmsbytes - 1); crcst++); + + if (crcst < parmsbytes - 1) { + gp->file_crc = atoi(parms + crcst); + + for (datest = crcst; (!(parms[datest - 2] == '#' + && parms[datest - 1] == '$')); datest++); + + date = (int) strtol(parms + datest, NULL, 16); + ft.tm_sec = (date & 0x1F) * 2; + date >>= 5; + ft.tm_min = date & 0x3F; + date >>= 6; + ft.tm_hour = date & 0x1F; + date >>= 5; + ft.tm_mday = date & 0x1F; + date >>= 5; + ft.tm_mon = date & 0x0F; + date >>= 4; + ft.tm_year = (date & 0x7F) + 70; + ft.tm_isdst = 0; + ft.tm_yday = 0; + ft.tm_wday = 0; + gp->ut.actime = mktime(&ft); + gp->ut.modtime = gp->ut.actime; + + for (namest = datest; (parms[namest - 1] != '#' && + namest < parmsbytes - 1); namest++); + } else { + gp->ut.actime = 0; + gp->ut.modtime = 0; + } + + gp->dwn_cnt = atol(parms); + strcpy(gp->file_name, STD_DWN_DIR); + + if (crcst == parmsbytes - 1 || datest - crcst > 7 || namest - datest > 10) { + *swin = opnstatw(mode, wintab, "Remote starts AutoBin transfer", 6, 52); + gp->new_header = FALSE; + wrdstatw(*swin, "old styled Header (no filename)"); + strcat(gp->file_name, address[0]); + strcat(gp->file_name, ".dwnfile"); + } else { + *swin = opnstatw(mode, wintab, "Remote starts AutoBin transfer", 10, 52); + gp->new_header = TRUE; + for (cnt = parmsbytes - namest; !(parms[cnt + namest - 1] == '\\' || parms[cnt + namest - 1] == '/') && cnt > 0; cnt--); + strncpy(s, &parms[namest + cnt], parmsbytes - namest - cnt); + convert_upper_lower(s, parmsbytes - namest - cnt); + strncat(gp->file_name, s, parmsbytes - namest - cnt); + gp->file_name[strlen(gp->file_name) + parmsbytes - namest - cnt - 1] = 0; + + sprintf(s, "size of file : %u", (unsigned int) gp->dwn_cnt); + wrdstatw(*swin, s); + sprintf(s, "filename : %s", gp->file_name); + wrdstatw(*swin, s); + sprintf(s, "last mod. date : %02i.%02i.%04i", ft.tm_mday, ft.tm_mon, ft.tm_year + 1900); + wrdstatw(*swin, s); + sprintf(s, "last mod. time : %02i:%02i:%02i", ft.tm_hour, ft.tm_min, ft.tm_sec); + wrdstatw(*swin, s); + } + + dupdstatw(*swin, "Bytes to receive: ", TRUE); + + if ((gp->dwn_file = open(gp->file_name, O_RDWR | O_CREAT, 0666)) == -1) { + sprintf(s, "Unable to open %s", gp->file_name); + statline(mode, s); + if (write(fd, "#ABORT#\r", 8) == -1) { + perror("write"); + gp->dwn_cnt = 0; + gp->file_name[0] = '\0'; + return -1; + } + } + if (bytes == 1) { + if (write(fd, "#OK#\r", 5) == -1) { + perror("write"); + gp->dwn_cnt = 0; + gp->file_name[0] = '\0'; + return -1; + } + gp->calc_crc = 0; + } else { + write(gp->dwn_file, buf, bytes); + gp->calc_crc = calc_crc(buf, bytes, 0); + gp->dwn_cnt -= bytes; + } + + return 0; +} + +int ab_down(int mode, WINDOW * swin, wint * wintab, char buf[], int *bytes, t_gp * gp) +{ + int extrach = 0; + char s[80]; + + if (strncmp(buf, "#ABORT#\r", 8) == 0 && *bytes == 8) { + gp->dwn_cnt = 0; + close(gp->dwn_file); + statline(mode, "Remote aborts AutoBin transfer!"); + *bytes = 0; + if (mode != RAWMODE) { + delwin(swin); + winclose(wintab); + } else { + printf("\n"); + } + + return 0; + } + if (gp->dwn_cnt < *bytes) { + extrach = *bytes - gp->dwn_cnt; + *bytes = gp->dwn_cnt; + } + if (write(gp->dwn_file, buf, *bytes) != *bytes) { + close(gp->dwn_file); + gp->dwn_cnt = 0; + statline(mode, "Error while writing download file. Download aborted."); + + if (mode != RAWMODE) { + delwin(swin); + winclose(wintab); + } else { + printf("\n"); + } + } else { + gp->calc_crc = calc_crc(buf, *bytes, gp->calc_crc); + gp->dwn_cnt -= *bytes; + + if (gp->dwn_cnt == 0) { + if (mode != RAWMODE) { + delwin(swin); + winclose(wintab); + } else + printf("\n"); + + strcpy(s, "AutoBin download finished "); + if (gp->new_header) + if (gp->calc_crc == gp->file_crc) + strcat(s, "CRC check ok"); + else { + strcat(s, "CRC check failed!"); + } else { + sprintf(s + strlen(s), "CRC=%u", gp->calc_crc); + } + statline(mode, s); + close(gp->dwn_file); + utime(gp->file_name, &gp->ut); + if (extrach != 0) { + memmove(buf, buf + *bytes, extrach); + *bytes = extrach; + } else + *bytes = 0; + } else { + sprintf(s, "%u", (unsigned int) gp->dwn_cnt); + dupdstatw(swin, s, FALSE); + *bytes = 0; + } + } + return 0; +} + +int start_screen(char *call[]) +{ + int cnt; + char idString[11]; + sprintf(idString, " %8s ", call[0]); + + if ((win = initscr()) == NULL) + return -1; + + attron(A_REVERSE); + move(0, 0); + addstr(idString); + addch(ACS_VLINE); + addstr("--------"); + addch(ACS_VLINE); + for (cnt = STATW_STAT; cnt <= 80; cnt++) + addch(' '); + attroff(A_REVERSE); + + noecho(); + raw(); + nodelay(win, TRUE); + keypad(win, TRUE); + refresh(); + + return 0; +} + +int start_slave_mode(wint * wintab, t_win * win_in, t_win * win_out) +{ + win_in->max_y = LINES - 2; + win_in->max_x = COLS; + win_in->ptr = winopen(wintab, win_in->max_y + 1, win_in->max_x, 1, 0, FALSE); + win_out->ptr = win_in->ptr; + + scrollok(win_in->ptr, TRUE); + + wclear(win_out->ptr); + wrefresh(win_out->ptr); + + win_out->bytes = 0; + win_out->curs_pos = 0; + win_in->bytes = 0; + win_in->curs_pos = 0; + + return 0; +} + +int start_talk_mode(wint * wintab, t_win * win_in, t_win * win_out) +{ + int cnt; + WINDOW *win; + + win_out->max_y = 4; /* TXLINES */ + win_out->max_x = COLS; + win_in->max_y = (LINES - 4) - win_out->max_y; + win_in->max_x = COLS; + + win_out->ptr = winopen(wintab, win_out->max_y + 1, win_out->max_x, (win_in->max_y + 3), 0, FALSE); + win_in->ptr = winopen(wintab, win_in->max_y + 1, win_in->max_x, 1, 0, FALSE); + win = winopen(wintab, 1, win_out->max_x, win_in->max_y + 2, 0, FALSE); + + for (cnt = 0; cnt < COLS; cnt++) + waddch(win, '-'); + wrefresh(win); + + scrollok(win_in->ptr, TRUE); + scrollok(win_out->ptr, TRUE); + + wclear(win_out->ptr); + wrefresh(win_out->ptr); + wclear(win_in->ptr); + wrefresh(win_in->ptr); + + win_out->bytes = 0; + win_out->curs_pos = 0; + win_in->bytes = 0; + win_out->curs_pos = 0; + + return 0; +} + +int change_mode(int oldmode, int newmode, wint * wintab, t_win * win_in, t_win * win_out, char *call[]) +{ + switch (oldmode) { + case RAWMODE: + if (newmode == TALKMODE) { + start_screen(call); + start_talk_mode(wintab, win_in, win_out); + } + if (newmode == SLAVEMODE) { + start_screen(call); + start_slave_mode(wintab, win_in, win_out); + } + break; + + case TALKMODE: + if (newmode == RAWMODE) { + wclear(win_out->ptr); + wrefresh(win_out->ptr); + wclear(win_in->ptr); + wrefresh(win_in->ptr); + wintab->next = 0; + endwin(); + } + if (newmode == SLAVEMODE) { + delwin(win_out->ptr); + delwin(win_in->ptr); + wintab->next = 0; + start_slave_mode(wintab, win_in, win_out); + } + break; + + case SLAVEMODE: + if (newmode == RAWMODE) { + wclear(win_out->ptr); + wrefresh(win_out->ptr); + wintab->next = 0; + endwin(); + } + if (newmode == TALKMODE) { + delwin(win_out->ptr); + wintab->next = 0; + start_talk_mode(wintab, win_in, win_out); + } + break; + } + + return newmode; +} + +void writeincom(int mode, t_win * win_in, unsigned char buf[], int bytes) +{ + int cnt; + + if (mode & RAWMODE) { + write(STDOUT_FILENO, buf, bytes); + return; + } + for (cnt = 0; cnt < bytes; cnt++) { + switch (buf[cnt]) { + case 201: + case 218: + waddch(win_in->ptr, ACS_ULCORNER); + break; + case 187: + case 191: + waddch(win_in->ptr, ACS_URCORNER); + break; + case 200: + case 192: + waddch(win_in->ptr, ACS_LLCORNER); + break; + case 188: + case 217: + waddch(win_in->ptr, ACS_LRCORNER); + break; + case 204: + case 195: + waddch(win_in->ptr, ACS_LTEE); + break; + case 185: + case 180: + waddch(win_in->ptr, ACS_RTEE); + break; + case 203: + case 194: + waddch(win_in->ptr, ACS_TTEE); + break; + case 202: + case 193: + waddch(win_in->ptr, ACS_BTEE); + break; + case 205: + case 196: + waddch(win_in->ptr, ACS_HLINE); + break; + case 186: + case 179: + waddch(win_in->ptr, ACS_VLINE); + break; + case 129: + waddch(win_in->ptr, 252); /*u umlaut */ + break; + case 132: + waddch(win_in->ptr, 228); /*a umlaut */ + break; + case 142: + waddch(win_in->ptr, 196); /*A umlaut */ + break; + case 148: + waddch(win_in->ptr, 246); /*o umlaut */ + break; + case 153: + waddch(win_in->ptr, 214); /*O umlaut */ + break; + case 154: + waddch(win_in->ptr, 220); /*U umlaut */ + break; + case 225: + waddch(win_in->ptr, 223); /*sz */ + break; + default: + { + if (buf[cnt] > 127) + waddch(win_in->ptr, '.'); + else + waddch(win_in->ptr, buf[cnt]); + } + } + } + +/* waddnstr(win_in->ptr, buf, bytes); */ + wrefresh(win_in->ptr); + + return; +} + +int getstring(wint * wintab, char text[], char buf[]) +{ + int c; + int ypos = 0, xpos = 0; + int bytes = 0; + + WINDOW *win = winopen(wintab, 3, COLS, 10, 0, TRUE); + + wmove(win, 1, 2); + waddstr(win, text); + wrefresh(win); + + do { + c = getch(); + if (c != ERR) { + switch (c) { + case KEY_BACKSPACE: + case 127: + { + getyx(win, ypos, xpos); + if (xpos > 0 && bytes > 0) { + wmove(win, ypos, --xpos); + waddch(win, ' '); + wmove(win, ypos, xpos); + bytes--; + } + } + break; + case (int) '\n': + case (int) '\r': + case KEY_ENTER: + { + waddch(win, '\n'); + buf[bytes++] = (char) '\n'; + wrefresh(win); + buf[bytes] = 0; + } + break; + default: + { + waddch(win, (char) c); + buf[bytes++] = (char) c; + } + } + wrefresh(win); + } + } + while (c != '\n' && c != '\r' && c != KEY_ENTER); + delwin(win); + winclose(wintab); + return 0; +} + +int readoutg(t_win * win_out, wint * wintab, menuitem * top, char buf[], int keyesc) +{ + int out_cnt; + int c; + int ypos = 0, xpos = 0; + int value; + + c = getch(); + if (c == ERR) + return 0; + + if (c == keyesc) { + if ((value = top_menu(wintab, top, 1)) == 0) + return 0; + buf[0] = '~'; + switch (value) { + case 0x01: + { + buf[1] = 'r'; + return 2; + } + case 0x02: + { + buf[1] = '.'; + return 2; + } + case 0x11: + { + buf[1] = 'o'; + getstring(wintab, "Please enter filename: ", &buf[2]); + return strlen(buf); + } + case 0x12: + { + buf[1] = 'c'; + return 2; + } + case 0x13: + case 0x14: + case 0x15: + { + switch (value) { + case 0x13: + buf[1] = 'u'; + break; + case 0x14: + buf[1] = 'b'; + break; + case 0x15: + buf[1] = 'a'; + } + getstring(wintab, "Please enter filename: ", buf + 2); + return strlen(buf); + } + case 0x21: + { + buf[1] = '1'; + return 2; + } + case 0x22: + { + buf[1] = '2'; + return 2; + } + case 0x23: + { + buf[1] = '0'; + return 2; + } + case 0x31: + return -1; + } + wrefresh(win_out->ptr); + return 2; + } + switch (c) { + case KEY_BACKSPACE: + case 127: + { + getyx(win_out->ptr, ypos, xpos); + if (win_out->bytes > 0) { + if (win_out->curs_pos < win_out->bytes) { + mvwaddnstr(win_out->ptr, ypos, --xpos, &win_out->string[win_out->curs_pos], win_out->bytes - win_out->curs_pos); + waddch(win_out->ptr, ' '); + memmove(&win_out->string[win_out->curs_pos - 1], &win_out->string[win_out->curs_pos], win_out->bytes - win_out->curs_pos); + } else + mvwaddch(win_out->ptr, ypos, --xpos, ' '); + + wmove(win_out->ptr, ypos, xpos); + win_out->bytes--; + win_out->curs_pos--; + } + } + break; + case KEY_LEFT: + if (win_out->curs_pos > 0) { + win_out->curs_pos--; + getyx(win_out->ptr, ypos, xpos); + wmove(win_out->ptr, ypos, xpos - 1); + } + break; + case KEY_RIGHT: + if (win_out->curs_pos < win_out->bytes) { + win_out->curs_pos++; + getyx(win_out->ptr, ypos, xpos); + wmove(win_out->ptr, ypos, xpos + 1); + } + break; + case KEY_ENTER: + case (int) '\n': + case (int) '\r': + { + if (win_out->curs_pos < win_out->bytes) { + getyx(win_out->ptr, ypos, xpos); + wmove(win_out->ptr, ypos, xpos + win_out->bytes - win_out->curs_pos); + } + waddch(win_out->ptr, '\n'); + win_out->string[win_out->bytes++] = (char) '\n'; + wrefresh(win_out->ptr); + strncpy(buf, win_out->string, win_out->bytes); + wrefresh(win_out->ptr); + out_cnt = win_out->bytes; + win_out->bytes = 0; + win_out->curs_pos = 0; + return out_cnt; + } + break; + default: + { + waddch(win_out->ptr, (char) c); + if (win_out->curs_pos < win_out->bytes) { + getyx(win_out->ptr, ypos, xpos); + waddnstr(win_out->ptr, &win_out->string[win_out->curs_pos], win_out->bytes - win_out->curs_pos); + memmove(&win_out->string[win_out->curs_pos + 1], &win_out->string[win_out->curs_pos], win_out->bytes - win_out->curs_pos); + win_out->string[win_out->curs_pos] = (char) c; + wmove(win_out->ptr, ypos, xpos); + } else + win_out->string[win_out->bytes] = (char) c; + + win_out->bytes++; + win_out->curs_pos++; + } + } + wrefresh(win_out->ptr); + return 0; +} +void writemsg(char fname[], char caller[]) +{ + char text_row[255]; + char *text_ptr; + char buf[255]; + FILE *f = fopen(fname, "r"); + + if (f == NULL) { + perror(fname); + return; + } + do { + if (fgets(text_row, 255, f) != 0) { + text_row[strlen(text_row) - 1] = '\r'; + text_ptr = strchr(text_row, '$'); + if (text_ptr != NULL) { + strcpy(buf, text_ptr + 2); + switch (*(text_ptr + 1)) { + case 'c': + { + strcpy(text_ptr, caller); + strcat(text_ptr, buf); + } + } + } + write(fd, text_row, strlen(text_row)); + } + } + while (!feof(f)); +} + +void remotecommand(char buf[], int bytes) +{ + int firstchar; + if (bytes == 0) + return; + + switch (buf[0]) { + case 'e': + case 'E': + { + for (firstchar = 0; buf[firstchar] != ' '; firstchar++); + firstchar++; + buf[bytes] = '\n'; + convert_lf_cr(buf + firstchar, bytes - firstchar + 1); + write(fd, buf + firstchar, bytes - firstchar + 1); + } + break; + default: + write(fd, "Unknown command\r", 16); + } +} + +int compstr(const char st1[], char st2[], int maxbytes) +{ + int cnt; + for (cnt = 0; st1[cnt] == st2[cnt] && cnt + 1 < maxbytes && st1[cnt + 1] != 0; cnt++); + if (st1[cnt] != st2[cnt]) + return -1; + + if (st1[cnt + 1] == 0) + return 0; + if (cnt == maxbytes - 1) + return -2; + + return -1; +} + +int eol(char c) +{ + + if (c == '\r' || c == '\n' || c == 0x1A) + return TRUE; + else + return FALSE; +} + +int searche_key_words(char buf[], int *bytes, char *parms, int *parmsbytes, char restbuf[], int *restbytes) +{ + static char cmpstr[MAX_CMPSTRLEN]; + static int cmpstrbyte = 0; + static int command = -1; + + int cmdstpos = 0; + int cnt = 0; + int t = 0; + + if (cmpstrbyte != 0) { + memmove(buf + cmpstrbyte, buf, *bytes); + *bytes += cmpstrbyte; + strncpy(buf, cmpstr, cmpstrbyte); + cmpstrbyte = 0; + for (cnt = 0; !eol(buf[cnt]) && cnt < *bytes - 1; cnt++); + if (cnt == *bytes - 1 && !eol(buf[cnt])) { + printf("Problem!!!\n"); + command = -1; + *restbytes = 0; + *parmsbytes = 0; + return -1; + } + } + if (command == -1) { + cnt = 0; + do { + command = 0; + cmdstpos = cnt; + + do { + if ((t = compstr(key_words[command], &buf[cnt], *bytes - cnt)) != -1) + break; + } + while (*key_words[++command] != '\0'); + + for (; !eol(buf[cnt]) && cnt < *bytes - 1; cnt++); + + if (cnt < *bytes - 1) + cnt++; + else + break; + } + while (t == -1); + if (t < 0) + command = -1; + } + if (t == -2 || (command != -1 && cnt == *bytes - 1 && !eol(buf[*bytes - 1]))) { + cmpstrbyte = *bytes - cmdstpos; + strncpy(cmpstr, &buf[cmdstpos], cmpstrbyte); + cmpstr[cmpstrbyte] = 0; + *bytes -= cmpstrbyte; + *restbytes = 0; + return -1; + } + if (t == -1) { + command = -1; + cmpstrbyte = 0; + *restbytes = 0; + return -1; + } + t = cmdstpos + strlen(key_words[command]); + *restbytes = *bytes - cnt; + strncpy(parms, &buf[t], cnt - t); + *parmsbytes = cnt - t; + strncpy(restbuf, buf + cnt, *restbytes); + *bytes = cmdstpos; + + t = command; + command = -1; + return t; +} + +int sevenplname(int mode, WINDOW ** swin, wint * wintab, int *f, int* logfile, char parms[], int parmsbytes, char buf[], int bytes) +{ + int cnt; + int part; + int nrparts; + int lines; + char orgn[13]; + char prtn[13]; + char strn[255]; + char v[20]; + char s[80]; + if (parmsbytes >= 40) + if (strcmp(" of ", &parms[3]) == 0 + || parmsbytes < 41 + || parms[10] != ' ' + || parms[23] != ' ' + || parms[31] != ' ' + || parms[36] != ' ' + || parms[40] != ' ') { + return -1; + } + part = atof(parms); + lines = (int) strtol(parms + 37, NULL, 16); + nrparts = (int) strtol(parms + 7, NULL, 10); + + strncpy(orgn, &parms[11], 12); + convert_upper_lower(orgn, 12); + for (cnt = 11; orgn[cnt] == ' '; cnt--); + orgn[cnt + 1] = 0; + if (orgn[cnt - 3] == '.') { + strncpy(prtn, orgn, cnt - 2); + if (nrparts == 1) + sprintf(prtn + cnt - 2, "7pl"); + else + sprintf(prtn + cnt - 2, "p%02x", part); + } else { + strcpy(prtn, orgn); + if (nrparts == 1) + sprintf(prtn + cnt, ".7pl"); + else + sprintf(prtn + cnt, ".p%02x", part); + } + + strcpy(strn, STD_DWN_DIR); + strcat(strn, prtn); + + for (cnt = 0; parms[cnt + 41] != ')' && cnt + 41 != parmsbytes; cnt++); + if (parms[cnt + 41] != ')') { + return -1; + } + strncpy(v, &parms[41], cnt + 1); + v[cnt + 1] = 0; + *swin = opnstatw(mode, wintab, "Remote starts 7+ Download", 11, 55); + sprintf(s, "7plus version : %s", v); + wrdstatw(*swin, s); + sprintf(s, "Name of decoded file : %s", orgn); + wrdstatw(*swin, s); + sprintf(s, "Storagename : %s", strn); + wrdstatw(*swin, s); + sprintf(s, "Parts : %i", nrparts); + wrdstatw(*swin, s); + sprintf(s, "Number of this Part : %i", part); + wrdstatw(*swin, s); + sprintf(s, "Lines : %i", lines); + wrdstatw(*swin, s); + dupdstatw(*swin, "Outstanding lines : ", TRUE); + + if (*f != -1) { + close(*f); + } + if ((*f = open(strn, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) { + sprintf(s, "Unable to open %s", strn); + statline(mode, s); + } + else + if (*logfile != -1) + { + sprintf(s, "*** 7plus download into file: %s ***\n", strn); + write(*logfile, s, strlen(s)); + } + + write(*f, key_words[2], strlen(key_words[2])); + convert_cr_lf(parms, parmsbytes); + write(*f, parms, parmsbytes); + + return lines; +} +void statbits(int mode, char stat, int m) +{ + if (mode == RAWMODE) + return; + move(0, STATW_BITS + m); + attron(A_REVERSE); + addch(stat); + attroff(A_REVERSE); + refresh(); + return; +} + + +int cmd_call(char *call[], int mode) +{ + menuitem con[] = + { + {"~Reconnect", 'R', M_ITEM, (void *) 0x01}, + {"~Exit", 'E', M_ITEM, (void *) 0x02}, + {"\0", 0, M_END, 0} + }; + + menuitem fil[] = + { + {"~Open Logfile", 'O', M_ITEM, 0}, + {"~Close Logfile", 'C', M_ITEM, 0}, + {"Send ~Textfile", 'T', M_ITEM, 0}, + {"Send ~Binary", 'B', M_ITEM, 0}, + {"Send ~AutoBin", 'A', M_ITEM, 0}, + {"\0", 0, M_END, 0} + }; + + menuitem mod[] = + { + {"~Slavemode", 'S', M_ITEM, 0}, + {"~Talkmode", 'T', M_ITEM, 0}, + {"~Rawmode", 'R', M_ITEM, 0}, + {"\0", 0, M_END, 0} + }; + + menuitem win[] = + { + {"~Clear", 'C', M_ITEM, 0}, + {"~Resize", 'R', M_ITEM, 0}, + {"\0", 0, M_END, 0} + }; + + menuitem top[] = + { + {"~Connect", 'C', M_P_DWN, con}, + {"~File", 'F', M_P_DWN, fil}, + {"~Mode", 'M', M_P_DWN, mod}, + {"~Window", 'W', M_P_DWN, win}, + {"\0", 0, M_END, 0} + }; + + wint wintab; + fd_set sock_read; + fd_set sock_write; + char buf[MAX_BUFLEN]; + char restbuf[MAX_PACKETLEN]; + char parms[256]; + int sevenplus = FALSE; + int sevenplcnt = 0; + int bytes; + int restbytes; + int parmsbytes; + int com_num; + int logfile = -1; + int uploadfile = -1; + int downloadfile = -1; + int binup = FALSE; + long uplsize = 0; + long uplpos = 0; + char uplbuf[128]; /* Upload buffer */ + int upldp = 0; + int upllen = 0; + char *c, *t; + int extrach = 0; + t_gp gp; + t_win win_in; + t_win win_out; + WINDOW *swin = 0; + int cnt; + int crc = 0; + char s[80]; + int flags = 0; + + init_crc(); + + gp.dwn_cnt = 0; + wintab.next = 0; + + if ((fd = connect_to(call)) == -1) + return FALSE; + + interrupted = FALSE; + signal(SIGQUIT, cmd_intr); + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + + fcntl(fd, F_SETFL, O_NONBLOCK); + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + + if (mode != RAWMODE) + start_screen(call); + switch (mode) { + case TALKMODE: + start_talk_mode(&wintab, &win_in, &win_out); + break; + case SLAVEMODE: + start_slave_mode(&wintab, &win_in, &win_out); + break; + case RAWMODE: + printf("Rawmode\n"); + } + + while (TRUE) { + FD_ZERO(&sock_read); + FD_SET(STDIN_FILENO, &sock_read); + FD_SET(fd, &sock_read); + FD_ZERO(&sock_write); + + if (uploadfile != -1) + FD_SET(fd, &sock_write); + + if (select(fd + 1, &sock_read, &sock_write, NULL, NULL) == -1) { + if (!interrupted && errno == EAGAIN) + continue; + if (!interrupted) + perror("select"); + break; + } + if (FD_ISSET(fd, &sock_read)) { + bytes = read(fd, buf, 511); + if (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN) { + if (errno != ENOTCONN) + perror("read"); + break; + } + if (gp.dwn_cnt != 0) { + ab_down(mode, swin, &wintab, buf, &bytes, &gp); + if (bytes == 0) + continue; + } + do { + com_num = searche_key_words(buf, &bytes, parms, &parmsbytes, restbuf, &restbytes); + + if (bytes != 0) { + convert_cr_lf(buf, bytes); + if (!sevenplus) { + + writeincom(mode, &win_in, buf, bytes); + } else { + for (cnt = 0; cnt < bytes; cnt++) + if (eol(buf[cnt])) + sevenplcnt--; + dupdstatw(swin, s, FALSE); + } + if (downloadfile != -1) + { + if (write(downloadfile, buf, bytes) != bytes) + { + close(downloadfile); + downloadfile = -1; + statline(mode, "Error while writing file. Downloadfile closed."); + } + } + else + if (logfile != -1) { + if (write(logfile, buf, bytes) != bytes) { + close(logfile); + logfile = -1; + statline(mode, "Error while writing log. Log closed."); + } + } + } + switch (com_num) { + case 0: + { +#ifdef 0 /* FIXME! We should, no: WE MUST be able to turn off */ + /* all remote commands to avoid mail bombs generating */ + /* offensive mails with //e while sucking the BBS */ + + remotecommand(parms, parmsbytes); +#endif + } + break; + case 1: + { + start_ab_download(mode, &swin, &wintab, parms, parmsbytes, restbuf, restbytes, &gp, call); + restbytes = 0; + extrach = 0; + } + break; + case 2: + { + if ((sevenplcnt = sevenplname(mode, &swin, &wintab, &downloadfile, &logfile, parms, parmsbytes, buf, bytes)) != -1) + sevenplus = TRUE; + } + break; + case 3: + { + if (!sevenplus) + break; + write(downloadfile, key_words[3], strlen(key_words[3])); + convert_cr_lf(parms, parmsbytes); + write(downloadfile, parms, parmsbytes); + if (mode != RAWMODE) { + delwin(swin); + winclose(&wintab); + } else + printf("\n"); + statline(mode, "7+ Download finished."); + sevenplus = FALSE; + close(downloadfile); + downloadfile = -1; + } + break; + } + + strncpy(buf, restbuf, restbytes); + bytes = restbytes; + } + while (restbytes != 0); + } + if (FD_ISSET(STDIN_FILENO, &sock_read)) { + if ((mode & RAWMODE) == RAWMODE) + bytes = read(STDIN_FILENO, buf, 511); + else { + bytes = readoutg(&win_out, &wintab, top, buf, 0x1d); + if (bytes == -1) { + wclear(win_in.ptr); + wrefresh(win_in.ptr); + wclear(win_out.ptr); + wrefresh(win_out.ptr); + bytes = 0; + } + } + if (bytes > 0) + statline(mode, ""); + + if (bytes > 1 && *buf == '~') { + buf[bytes] = 0; + + switch (buf[1]) { + case '.': + { + bytes = 0; + interrupted = TRUE; + } + break; + case '!': + change_mode(mode, RAWMODE, &wintab, &win_in, &win_out, call); + if (buf[2] != '\0' && buf[2] != '\n') { + c = buf + 2; + if ((t = strchr(c, '\n')) != NULL) + *t = '\0'; + } else { + if ((c = getenv("SHELL")) == NULL) + c = "/bin/sh"; + } + + fcntl(STDIN_FILENO, F_SETFL, 0); + printf("\n[Spawning subshell]\n"); + system(c); + printf("\n[Returned to connect]\n"); + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + change_mode(RAWMODE, mode, &wintab, &win_in, &win_out, call); + continue; + case 'z': + case 'Z': + case 'Z' - 64: + fcntl(STDIN_FILENO, F_SETFL, 0); + kill(getpid(), SIGSTOP); + statline(mode, "Resumed"); + fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK); + continue; + case '?': + case 'h': + case 'H': + printf("\n\rTilde escapes:\n\r. close\n\r! shell\n\rZ suspend\n\rs Stop upload\n\ro Open log\n\rc Close log\n\ru Upload\n\ryd YAPP Download\n\ryu YAPP Upload\n\r"); + continue; + case 'S': + case 's': + if (uploadfile != -1) { + statline(mode, "Upload file closed"); + close(uploadfile); + uploadfile = -1; + } else { + statline(mode, "No upload in progress"); + } + continue; + case 'A': + case 'a': + case 'b': + case 'B': + case 'u': + case 'U': + if (uploadfile != -1) { + statline(mode, "Already uploading"); + continue; + } + if ((t = strchr(buf, '\n')) != NULL) + *t = '\0'; + t = buf + 2; + while (*t != '\0' && isspace(*t)) + t++; + if (*t == '\0') { + statline(mode, "Upload requires a filename"); + continue; + } + uploadfile = open(t, O_RDONLY); + if (uploadfile == -1) { + statline(mode, "Unable to open upload file"); + continue; + } + if (lseek(uploadfile, 0L, SEEK_END) != -1) + uplsize = lseek(uploadfile, 0L, SEEK_CUR); + else + uplsize = 0; + lseek(uploadfile, 0L, SEEK_SET); + uplpos = 0; + upldp = -1; + upllen = 0; + if (uplsize != -1) { + sprintf(s, "Uploading %ld bytes from %s", uplsize, t); + swin = opnstatw(mode, &wintab, s, 6, 50); + dupdstatw(swin, "bytes sent : ", TRUE); + } else { + sprintf(s, "Uploading from %s", t); + swin = opnstatw(mode, &wintab, s, 6, 50); + dupdstatw(swin, "bytes sent : ", TRUE); + } + switch (buf[1]) { + case 'a': + case 'A': + { + binup = TRUE; + crc = 0; + + do { + upllen = read(uploadfile, uplbuf, 128); + + if (upllen == -1) { + close(uploadfile); + uploadfile = -1; + delwin(swin); + winclose(&wintab); + sprintf(s, "Error reading upload file: upload aborted"); + statline(mode, s); + break; + } + crc = calc_crc(uplbuf, upllen, crc); + } + while (upllen > 0); + lseek(uploadfile, 0L, SEEK_SET); + sprintf(s, "#BIN#%ld#$%u#|000000#%s\r", uplsize, crc, t); + write(fd, s, strlen(s)); + uplpos = 0; + upldp = -1; + upllen = 0; + } + break; + case 'b': + case 'B': + binup = TRUE; + break; + case 'u': + case 'U': + binup = FALSE; + } + continue; + case 'O': + case 'o': + if ((t = strchr(buf, '\n')) != NULL) + *t = '\0'; + if (logfile != -1) { + close(logfile); + logfile = -1; + } + if (downloadfile != -1) + { + close(downloadfile); + downloadfile = -1; + } + t = buf + 2; + while (*t != '\0' && isspace(*t)) + t++; + if (*t == '\0') + t = "logfile.txt"; + if ((logfile = open(t, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1) { + sprintf(s, "Unable to open %s", buf + 2); + statline(mode, s); + } else + statbits(mode, 'L', 1); + continue; + case 'C': + case 'c': + if (logfile != -1) { + close(logfile); + logfile = -1; + statbits(mode, '-', 1); + } else { + statline(mode, "Log file not open"); + } + continue; + case 'Y': + case 'y': + cmd_yapp(buf + 2, bytes - 2); + continue; + case '~': + bytes--; + memmove(buf, buf + 1, strlen(buf)); + break; + case 'R': + case 'r': + flags |= FLAG_RECONNECT; + bytes = 0; + interrupted = TRUE; + continue; + case '0': + mode = change_mode(mode, RAWMODE, &wintab, &win_in, &win_out, call); + continue; + case '1': + mode = change_mode(mode, SLAVEMODE, &wintab, &win_in, &win_out, call); + continue; + case '2': + mode = change_mode(mode, TALKMODE, &wintab, &win_in, &win_out, call); + continue; + default: + statline(mode, "Unknown '~' escape. Type ~h for a list"); + continue; + } + } + /* if (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN) */ + /* if ((bytes == 0 && (mode & (TALKMODE|SLAVEMODE)) == 0) || (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN)) */ + if (interrupted || (bytes == -1 && errno != EWOULDBLOCK && errno != EAGAIN)) { + if (!interrupted) + perror("input"); + break; + } + if (bytes > 0) { + sevenplus = FALSE; + if (uploadfile != -1) { + statline(mode, "Ignored. Type ~s to stop upload"); + continue; + } + convert_lf_cr(buf, bytes); + + if (write(fd, buf, bytes) == -1) { + perror("write"); + break; + } + } + if (uploadfile != -1) { + if (uplsize == 0) { + close(uploadfile); + uploadfile = -1; + delwin(swin); + winclose(&wintab); + statline(mode, "Upload complete: 0 bytes"); + continue; + } + if (upldp == -1) { + upllen = read(uploadfile, uplbuf, 128); + + if (upllen == 0) { + close(uploadfile); + uploadfile = -1; + delwin(swin); + winclose(&wintab); + sprintf(s, "Upload complete: %ld bytes", uplpos); + statline(mode, s); + continue; + } + if (upllen == -1) { + close(uploadfile); + uploadfile = -1; + delwin(swin); + winclose(&wintab); + sprintf(s, "Error reading upload file: upload aborted at %ld bytes", uplpos); + statline(mode, s); + continue; + } + if (!binup) + convert_lf_cr(uplbuf, upllen); + + upldp = 0; + } + bytes = write(fd, uplbuf + upldp, upllen - upldp); + + if ((bytes == 0 || bytes == -1) && errno != EWOULDBLOCK && errno != EAGAIN) { + sprintf(s, "Write error during upload. Connection lost"); + statline(mode, s); + perror("write"); + break; + } +/* if (uplpos / 1024 != (uplpos + bytes) / 1024) + { */ + /* printf("\r%ld bytes sent ", uplpos + bytes); */ + sprintf(s, "%ld", uplpos + bytes); + dupdstatw(swin, s, FALSE); +/* } */ + + uplpos += bytes; + upldp += bytes; + + if (upldp >= upllen) + upldp = -1; + } + } + } + + close(fd); + + if (logfile != -1) { + close(logfile); + logfile = -1; + } + if (downloadfile != -1) { + close(downloadfile); + downloadfile = -1; + } + fcntl(STDIN_FILENO, F_SETFL, 0); + + signal(SIGQUIT, SIG_IGN); + signal(SIGINT, SIG_DFL); + + if (mode != RAWMODE) + endwin(); + + printf("*** Cleared\n"); + + if (flags & FLAG_RECONNECT) { + return TRUE; + } else { + return FALSE; + } +} + + +int main(int argc, char **argv) +{ + int p; + int mode = TALKMODE; + + while ((p = getopt(argc, argv, "b:dhm:p:rtvw:")) != -1) { + switch (p) { + case 'b': + if (*optarg != 'e' && *optarg != 'l') { + fprintf(stderr, "call: invalid argument for option '-b'\n"); + return 1; + } + backoff = *optarg == 'e'; + break; + case 'd': + debug = TRUE; + break; + case 'h': + mode = SLAVEMODE; + break; + case 'm': + if (*optarg != 's' && *optarg != 'e') { + fprintf(stderr, "call: invalid argument for option '-m'\n"); + return 1; + } + ax25mode = *optarg == 'e'; + break; + case 'p': + if ((paclen = atoi(optarg)) == 0) { + fprintf(stderr, "call: option '-p' requires a numeric argument\n"); + return 1; + } + if (paclen < 1 || paclen > 500) { + fprintf(stderr, "call: paclen must be between 1 and 500\n"); + return 1; + } + break; + case 'r': + mode = RAWMODE; + break; + case 't': + mode = TALKMODE; + break; + case 'v': + printf("call: %s\n", VERSION); + return 0; + case 'w': + if ((window = atoi(optarg)) == 0) { + fprintf(stderr, "call: option '-w' requires a numeric argument\n"); + return 1; + } + if (ax25mode) { + if (window < 1 || window > 63) { + fprintf(stderr, "call: window must be between 1 and 63 frames\n"); + return 1; + } + } else { + if (window < 1 || window > 7) { + fprintf(stderr, "call: window must be between 1 and 7 frames\n"); + return 1; + } + } + break; + case '?': + case ':': + fprintf(stderr, "usage: call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-t] [-v] [-w window] port callsign [[via] digipeaters...]\n"); + return 1; + } + } + + if (optind == argc || optind == argc - 1) { + fprintf(stderr, "usage: call [-b l|e] [-d] [-h] [-m s|e] [-p paclen] [-r] [-t] [-v] [-w window] port callsign [[via] digipeaters...]\n"); + return 1; + } + port = argv[optind]; + + if (ax25_config_load_ports() == 0) { + fprintf(stderr, "call: no AX.25 port data configured\n"); + return 1; + } + if (ax25_config_get_addr(port) == NULL) { + nr_config_load_ports(); + + if (nr_config_get_addr(port) == NULL) { + rs_config_load_ports(); + + if (rs_config_get_addr(port) == NULL) { + fprintf(stderr, "call: invalid port setting\n"); + return 1; + } else { + af_mode = AF_ROSE; + } + } else { + af_mode = AF_NETROM; + } + } else { + af_mode = AF_AX25; + } + + switch (af_mode) { + case AF_ROSE: + paclen = rs_config_get_paclen(port); + break; + + case AF_NETROM: + if (paclen == 0) + paclen = nr_config_get_paclen(port); + break; + case AF_AX25: + if (window == 0) + window = ax25_config_get_window(port); + if (paclen == 0) + paclen = ax25_config_get_paclen(port); + break; + } + + printf("GW4PTS AX.25 Connect v1.11\n"); + + while (cmd_call(argv + optind + 1, mode)) { + printf("Wait 60 sec before reconnect\n"); + sleep(60); + } + + return 0; +} diff --git a/call/call.h b/call/call.h new file mode 100644 index 0000000..5a7115d --- /dev/null +++ b/call/call.h @@ -0,0 +1,20 @@ +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +extern int fd; +extern int interrupted; +extern int paclen; + +/* In call.c */ +extern void convert_crlf(char *, int); +extern void convert_lfcr(char *, int); + +/* In yapp.c */ +extern void cmd_yapp(char *, int); + +/* In dostime.c */ +extern int yapp2unix(char *); +extern void unix2yapp( int, char *); diff --git a/call/crc.c b/call/crc.c new file mode 100644 index 0000000..637b0f5 --- /dev/null +++ b/call/crc.c @@ -0,0 +1,38 @@ + +/* tnt: Hostmode Terminal for TNC + Copyright (C) 1993 by Mark Wahl + For license details see documentation + Procedures for autobin-checksum (crc.c) + created: Mark Wahl DL4YBG 94/01/17 + updated: Mark Wahl DL4YBG 94/01/17 +*/ + +static int crcbit[8] = { + 0x9188,0x48c4,0x2462,0x1231,0x8108,0x4084,0x2042,0x1021 + }; + +static int bittab[8] = { 128,64,32,16,8,4,2,1 }; + +static int crctab[256]; + +void 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]; + } + } + } +} + +/* calculate checksum for autobin-protocol */ +unsigned int calc_crc(unsigned char* buf, int n, unsigned crc) +{ + while (--n >= 0) + crc = (crctab[(crc >> 8)] ^ ((crc << 8) | *buf++)) & 0xffff; + return crc; +} diff --git a/call/crc.h b/call/crc.h new file mode 100644 index 0000000..2f46059 --- /dev/null +++ b/call/crc.h @@ -0,0 +1,2 @@ +void init_crc(void); +unsigned int calc_crc(unsigned char*, int, unsigned); diff --git a/call/dostime.c b/call/dostime.c new file mode 100644 index 0000000..f162010 --- /dev/null +++ b/call/dostime.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + + +/* MS-DOS time/date conversion routines derived from: */ + +/* + * linux/fs/msdos/misc.c + * + * Written 1992,1993 by Werner Almesberger + */ + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +int date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + + month = ((date >> 5) & 15)-1; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + return secs; +} + + +/* Convert linear UNIX date to a MS-DOS time/date pair. */ + +void date_unix2dos(int unix_date,unsigned short *time, + unsigned short *date) +{ + int day,year,nl_day,month; + + *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ + (((unix_date/3600) % 24) << 11); + day = unix_date/86400-3652; + year = day/365; + if ((year+3)/4+365*year > day) year--; + day -= (year+3)/4+365*year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } + else { + nl_day = (year & 3) || day <= 59 ? day : day-1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) break; + } + *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); +} + +/* Convert yapp format 8 hex characters into Unix time */ + +int yapp2unix(char * ytime) +{ + int i; + unsigned short time,date; + if(strlen(ytime)!=8) return 0; + for(i=0;i<8;i++) if(!isxdigit(ytime[i])) return 0; + time = strtoul(ytime+4,(char **)NULL,16); + ytime[4]=0; + date = strtoul(ytime,(char **)NULL,16); + return(date_dos2unix(time,date)); + +} + +/* Convert unix time to 8 character yapp hex format */ + +void unix2yapp(int unix_date, char * buffer) +{ + unsigned short time,date; + date_unix2dos(unix_date,&time,&date); + sprintf(buffer,"%04X%04X",date,time); +} + diff --git a/call/menu.c b/call/menu.c new file mode 100644 index 0000000..e825789 --- /dev/null +++ b/call/menu.c @@ -0,0 +1,335 @@ +/* + * menu (c)1995 Alexander Tietzel (DG6XA) + * little Menu-System for use with ncurses + * date activity autor + * 22.07.1995 wininfo->wint (vector->single chain) Alexander Tietzel (DG6XA) + * 25.07.1995 some minor changes Alexander Tietzel (DG6XA) + */ + +#include +#include +#include "menu.h" + +typedef struct +{ + char *st_ptr; + int xpos; + char key; +} topmenuitem; + +WINDOW* winopen(wint *wtab, int nlines, int ncols, int begin_y, int begin_x, int border) +{ + + while (wtab->next != NULL) + wtab = wtab->next; + + wtab->next = (wint *)malloc(sizeof(wint)); + wtab = wtab->next; + + wtab->next = NULL; + + wtab->ptr = newwin(nlines, ncols, begin_y, begin_x); + + if (wtab->ptr == NULL) + return NULL; + + wtab->fline = begin_y; + wtab->lline = begin_y + nlines; + + if (border) + wborder(wtab->ptr, ACS_VLINE, ACS_VLINE, ACS_HLINE, ACS_HLINE, + ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER); + + return wtab->ptr; +} + +void winclose(wint *wtab) +{ + wint* awin; + wint* lwin; + int awin_lines; + + if (wtab->next == NULL) + return; + + lwin = wtab; + while (lwin->next->next != NULL) + lwin = lwin->next; + awin = lwin->next; + + awin_lines = awin->lline - awin->fline; + + while (wtab->next != NULL) { + if (awin->lline >= wtab->fline && awin->fline <= wtab->lline) { + if (wtab->fline <= awin->fline) { + if (wtab->lline < awin->lline) { + wtouchln(wtab->ptr, awin->fline - wtab->fline, + awin_lines - (awin->lline - wtab->lline), 1); + } else { + wtouchln(wtab->ptr, awin->fline - wtab->fline, + awin_lines, 1); + } + } else { + wtouchln(wtab->ptr, 0, awin_lines - wtab->fline + awin->fline, 1); + } + + wnoutrefresh(wtab->ptr); + } + + wtab = wtab->next; + } + + doupdate(); + lwin->next = 0; + free(awin); +} + +void menu_write_line(WINDOW *win, int ypos ,int menu_breite, int reverse, char st[]) +{ + int cnt; + int high = FALSE; + + if (reverse) + wattron(win, A_REVERSE); + + wmove(win, ypos + 1, 1); + for (cnt = 0; st[cnt] !=0; cnt++) { + if (st[cnt] == '~') { + if (!reverse) { + wattron(win, A_BOLD); + high = TRUE; + } + } else { + waddch(win, st[cnt]); + if (high == TRUE) { + high = FALSE; + wattroff(win, A_BOLD); + } + } + } + + for (cnt = strlen(st); cnt < menu_breite; cnt++) + waddch(win, ' '); + + if (reverse) + wattroff(win, A_REVERSE); +} + +int p_dwn_menu(wint *wtab, menuitem *menustr, int starty, int startx) +{ + int str_max_length = 0; + int cnt = 0, pos; + int ypos, oldypos; + int lines = 0; + int c; + WINDOW *menuwin; + + for (lines = 0; (*(menustr[lines].st_ptr) != 0); lines++) { + if (strlen(menustr[lines].st_ptr) > str_max_length) + str_max_length = strlen(menustr[lines].st_ptr); + } + + menuwin = winopen(wtab, lines + 2, str_max_length + 1, starty, startx, TRUE); + + wrefresh(menuwin); + + pos = 0; + menu_write_line(menuwin, 0, str_max_length, TRUE, menustr[0].st_ptr); + for (ypos = 1; ypos < lines; ypos++) + menu_write_line(menuwin, ypos, str_max_length, FALSE, menustr[ypos].st_ptr); + + wrefresh(menuwin); + ypos = 0; + + do { + while ((c=getch()) == ERR); + oldypos=ypos; + switch(c) { + case KEY_DOWN : + if (++ypos >= lines) ypos=0; + break; + case KEY_UP : + if (ypos == 0) + ypos = lines - 1; + else + ypos--; + break; + default : + if ((char)c >= 'a' && (char)c <= 'z') + c -= 'a'-'A'; + + for (cnt = 0; menustr[cnt].key !=(char)c && cnt < lines; cnt++); + if (menustr[cnt].key == (char)c) + ypos = cnt; + break; + } + + if (ypos != oldypos) { + menu_write_line(menuwin, ypos, str_max_length, TRUE, menustr[ypos].st_ptr); + menu_write_line(menuwin, oldypos, str_max_length, FALSE, menustr[oldypos].st_ptr); + + wrefresh(menuwin); + } + } while (c != KEY_ENTER && c != '\r' && c != '\n' && c != KEY_RIGHT && c != KEY_LEFT && c != 0x1b); + + delwin(menuwin); + + winclose(wtab); + + if (c == 0x1b) + return 0; + + + if (c == KEY_RIGHT || c == KEY_LEFT) + return c; + else + return ypos + 1; +} + +void menu_write_item(WINDOW *win, int xpos, int reverse, const char st[]) +{ + int cnt; + int high = FALSE; + + if (reverse) + wattron(win, A_REVERSE); + + wmove(win, 1, xpos + 1); + + for (cnt = 0; st[cnt] != 0; cnt++) { + if (st[cnt] == '~') { + if (!reverse) { + wattron(win, A_BOLD); + high = TRUE; + } + } else { + waddch(win, st[cnt]); + if (high) { + high = FALSE; + wattroff(win, A_BOLD); + } + } + } + + if (reverse) + wattroff(win, A_REVERSE); +} + + +int top_menu(wint* wtab,menuitem menustr[],int ystart) +{ + int str_max_length = 0; + int str_length=0; + int cnt, pos; + int xpos, oldxpos; + int ypos=0; + int items=0; + int c; + WINDOW *menuwin; + int items_xpos[12]; + + curs_set(0); /*cursor visibility off*/ + + for (items = 0; *(menustr[items].st_ptr) != 0; items++) { + if (items == 0) + items_xpos[0] = 1; + else + items_xpos[items] = items_xpos[items - 1] + str_length; + + if (strlen(menustr[items].st_ptr) > str_max_length) + str_max_length = strlen(menustr[items].st_ptr); + + str_length = strlen(menustr[items].st_ptr) + 1; + } + + menuwin = winopen(wtab, 3, 80, ystart, 0, TRUE); + + wrefresh(menuwin); + + pos = 0; + menu_write_item(menuwin, 1, TRUE, menustr[0].st_ptr); + + for (xpos = 1; xpos < items; xpos++) + menu_write_item(menuwin, items_xpos[xpos], FALSE, menustr[xpos].st_ptr); + + wrefresh(menuwin); + xpos = 0; + + do { + while ((c = getch()) == ERR); + + oldxpos = xpos; + + switch (c) { + case KEY_RIGHT: + if (++xpos >= items) + xpos = 0; + break; + + case KEY_LEFT: + if (xpos == 0) + xpos = items - 1; + else + xpos--; + break; + + case KEY_DOWN: + case KEY_ENTER: + case '\r': + case '\n': + ypos = 0; + do { + switch (ypos) { + case KEY_RIGHT: + if (++xpos >= items) + xpos = 0; + menu_write_item(menuwin, items_xpos[xpos], TRUE, menustr[xpos].st_ptr); + menu_write_item(menuwin, items_xpos[oldxpos], FALSE, menustr[oldxpos].st_ptr); + wrefresh(menuwin); + oldxpos = xpos; + break; + + case KEY_LEFT: + if (xpos == 0) + xpos = items - 1; + else + xpos--; + menu_write_item(menuwin, items_xpos[xpos], TRUE, menustr[xpos].st_ptr); + menu_write_item(menuwin, items_xpos[oldxpos], FALSE, menustr[oldxpos].st_ptr); + wrefresh(menuwin); + oldxpos = xpos; + break; + + } + + ypos = p_dwn_menu(wtab, (menuitem*)menustr[xpos].arg, ystart + 2, items_xpos[xpos] + 1); + touchwin(menuwin); + wrefresh(menuwin); + } while (ypos == KEY_RIGHT || ypos == KEY_LEFT); + break; + + default: + if ((char)c >= 'a' && (char)c <= 'z') + c -= 'a' - 'A'; + for (cnt = 0; menustr[cnt].key != (char)c && cnt <= items; cnt++); + if (menustr[cnt].key == (char)c) + xpos = cnt; + } + + if (xpos != oldxpos) { + menu_write_item(menuwin, items_xpos[xpos], TRUE, menustr[xpos].st_ptr); + menu_write_item(menuwin, items_xpos[oldxpos], FALSE, menustr[oldxpos].st_ptr); + wrefresh(menuwin); + } + + } while (ypos == 0 && c != 0x1b); + + delwin(menuwin); + curs_set(1); + winclose(wtab); + + if (c == 0x1b) + return 0; + + return (ypos & 0x0F) | ((xpos & 0x07) << 4); +} diff --git a/call/menu.h b/call/menu.h new file mode 100644 index 0000000..2067a3b --- /dev/null +++ b/call/menu.h @@ -0,0 +1,27 @@ +#define M_ITEM 0x01 +#define M_P_DWN 0x02 +#define M_END 0x03 + +typedef struct +{ + char* st_ptr; + char key; + int entr_type; + void* arg; +} menuitem; + +struct wint_s +{ + WINDOW* ptr; + int fline; + int lline; + struct wint_s* next; +}; +typedef struct wint_s wint; + +WINDOW* winopen(wint*, int, int, int, int, int); +void winclose(wint*); +void menu_write_line(WINDOW*, int, int,int, char*); +int p_dwn_menu(wint*, menuitem*, int, int); +void menu_write_item(WINDOW*, int,int, const char*); +int top_menu(wint*, menuitem*, int); 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; + } +} + -- cgit v1.2.3