summaryrefslogtreecommitdiffstats
path: root/call
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1999-06-07 10:23:42 +0200
committerRalf Baechle <ralf@linux-mips.org>1999-06-07 10:23:42 +0200
commit0fceb64d25ff3d9586549bb43d971c5eef904330 (patch)
treed4799d0fd53a3d8ae342c84f8ad4fb2ca2f14de0 /call
Import ax25-apps 0.0.1 from tarballax25-apps-0.0.1
Diffstat (limited to 'call')
-rw-r--r--call/Makefile.am25
-rw-r--r--call/Makefile.in370
-rw-r--r--call/call.1178
-rw-r--r--call/call.c1941
-rw-r--r--call/call.h20
-rw-r--r--call/crc.c38
-rw-r--r--call/crc.h2
-rw-r--r--call/dostime.c85
-rw-r--r--call/menu.c335
-rw-r--r--call/menu.h27
-rw-r--r--call/yapp.c840
11 files changed, 3861 insertions, 0 deletions
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 <TIETZE_A@etech.fh-hamburg.de>
+.br
+Joerg Reuter DL1BKE <jreuter@poboxes.com>
+.br
+Alan Cox GW4PTS <alan@cymru.net>
+.br
+Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>
+.br
+Steve Henson G6IXS <shenson@nyx.cs.du.edu>
+.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 <sys/types.h>
+#include <utime.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+#include <curses.h>
+
+#include <netax25/ax25.h>
+#include <netrom/netrom.h>
+#include <netrose/rose.h>
+
+#include <netax25/axlib.h>
+#include <netax25/axconfig.h>
+#include <netax25/nrconfig.h>
+#include <netax25/rsconfig.h>
+
+#include <config.h>
+
+#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 <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+
+/* 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 <curses.h>
+#include <stdlib.h>
+#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 <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <termios.h>
+#include <unistd.h>
+#include <linux/ax25.h>
+#include <sys/stat.h>
+
+#include "call.h"
+
+#define TIMEOUT 300 /* 5 Minutes */
+
+#define NUL 0x00
+#define SOH 0x01
+#define STX 0x02
+#define ETX 0x03
+#define EOT 0x04
+#define ENQ 0x05
+#define ACK 0x06
+#define DLE 0x10
+#define NAK 0x15
+#define CAN 0x18
+
+#define STATE_S 0
+#define STATE_SH 1
+#define STATE_SD 2
+#define STATE_SE 3
+#define STATE_ST 4
+#define STATE_R 5
+#define STATE_RH 6
+#define STATE_RD 7
+
+static int state;
+static int total = 0;
+
+static int readlen = 0;
+static int outlen = 0;
+static int outbufptr = 0;
+static unsigned char outbuffer[512];
+static char yappc; /* Nonzero if using YAPP C */
+
+static void Write_Status(char *s)
+{
+ fprintf(stdout, "State: %-60s\r", s);
+ fflush(stdout);
+}
+
+static void Send_RR(void)
+{
+ char buffer[2];
+
+ buffer[0] = ACK;
+ buffer[1] = 0x01;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_RF(void)
+{
+ char buffer[2];
+
+ buffer[0] = ACK;
+ buffer[1] = 0x02;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_RT(void)
+{
+ char buffer[2];
+
+ buffer[0] = ACK;
+ buffer[1] = ACK;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_AF(void)
+{
+ char buffer[2];
+
+ buffer[0] = ACK;
+ buffer[1] = 0x03;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_AT(void)
+{
+ char buffer[2];
+
+ buffer[0] = ACK;
+ buffer[1] = 0x04;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_NR(char *reason)
+{
+ char buffer[257];
+ int length;
+
+ if ((length = strlen(reason)) > 255)
+ length = 255;
+
+ buffer[0] = NAK;
+ buffer[1] = length;
+ memcpy(buffer + 2, reason, length);
+
+ write(fd, buffer, length + 2);
+}
+
+/* Send a Resume Sequence */
+
+static void Send_RS(int length)
+{
+ char buffer[256];
+ int len;
+
+ buffer[0] = NAK;
+ buffer[2] = 'R';
+ buffer[3] = 0;
+
+ len = sprintf(buffer + 4, "%d", length) + 5;
+
+ buffer[len] = 'C';
+ buffer[len + 1] = 0;
+ buffer[1] = len;
+
+ write(fd, buffer, len + 2);
+}
+
+static void Send_SI(void)
+{
+ char buffer[2];
+
+ buffer[0] = ENQ;
+ buffer[1] = 0x01;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_CN(char *reason)
+{
+ char buffer[257];
+ int length;
+
+ if ((length = strlen(reason)) > 255)
+ length = 255;
+
+ buffer[0] = CAN;
+ buffer[1] = length;
+ memcpy(buffer + 2, reason, length);
+
+ write(fd, buffer, length + 2);
+}
+
+static void Send_HD(char *filename, long length)
+{
+ char buffer[257];
+ char size_buffer[10];
+ int len_filename;
+ int len_size;
+ int len;
+ struct stat sb;
+
+ sprintf(size_buffer, "%ld", length);
+
+ len_filename = strlen(filename) + 1; /* Include the NUL */
+ len_size = strlen(size_buffer) + 1; /* Include the NUL */
+
+ len = len_filename + len_size;
+
+ if (!stat(filename, &sb))
+ {
+ unix2yapp(sb.st_mtime, buffer + len + 2);
+ len += 9;
+ }
+
+ buffer[0] = SOH;
+ buffer[1] = len;
+
+ memcpy(buffer + 2, filename, len_filename);
+ memcpy(buffer + len_filename + 2, size_buffer, len_size);
+
+ write(fd, buffer, len + 2);
+}
+
+static void Send_ET(void)
+{
+ char buffer[2];
+
+ buffer[0] = EOT;
+ buffer[1] = 0x01;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_DT(int length)
+{
+ char buffer[2];
+
+ if (length > 255) length = 0;
+
+ buffer[0] = STX;
+ buffer[1] = length;
+
+ write(fd, buffer, 2);
+}
+
+static void Send_EF(void)
+{
+ char buffer[2];
+
+ buffer[0] = ETX;
+ buffer[1] = 0x01;
+
+ write(fd, buffer, 2);
+}
+
+static unsigned char checksum(unsigned char *buf, int len)
+{
+ int i;
+ unsigned char sum = 0;
+
+ for (i = 0; i < len; i++)
+ sum += buf[i];
+
+ return sum;
+}
+
+static int yapp_download_data(int *filefd, unsigned char *buffer)
+{
+ int length,file_time;
+ char Message[50];
+
+ if (buffer[0] == CAN || buffer[0] == NAK)
+ {
+ Write_Status("RcdABORT");
+ return(FALSE);
+ }
+
+ switch (state)
+ {
+ case STATE_R:
+ if (buffer[0] == ENQ && buffer[1] == 0x01)
+ {
+ Send_RR();
+ Write_Status("RcvHeader");
+ state = STATE_RH;
+ break;
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_RH:
+ if (buffer[0] == SOH)
+ {
+ /* Parse header: 3 fields == YAPP C */
+ char *hptr, *hfield[3];
+ if ((length = buffer[1]) == 0) length = 256;
+ hptr = (char *)buffer + 2;
+ while (length > 0)
+ {
+ int hlen;
+ hlen = strlen(hptr) + 1;
+ hfield[(int)yappc++] = hptr;
+ hptr += hlen;
+ length -= hlen;
+ }
+
+ if (yappc < 3)
+ {
+ yappc = 0;
+ }
+ else
+ {
+ file_time = yapp2unix(hfield[2]);
+ yappc = 1;
+ }
+
+ if (*filefd == -1)
+ {
+ if ((*filefd = open(hfield[0], O_RDWR | O_APPEND | O_CREAT, 0666)) == -1)
+ {
+ printf("\n[Unable to open %s]\n", hfield[0]);
+ Send_NR("Invalid filename");
+ return(FALSE);
+ }
+ }
+
+ printf("Receiving %s %s %s", hfield[0], hfield[1],
+ yappc ? ctime((time_t *)&file_time) : " ");
+
+ if (yappc)
+ {
+ struct stat sb;
+
+ if (!fstat(*filefd, &sb) && sb.st_size)
+ Send_RS(sb.st_size);
+ else
+ Send_RT();
+ }
+ else
+ {
+ Send_RF();
+ }
+
+ state = STATE_RD;
+ break;
+ }
+
+ if (buffer[0] == ENQ && buffer[1] == 0x01)
+ {
+ break;
+ }
+
+ if (buffer[0] == EOT && buffer[1] == 0x01)
+ {
+ Send_AT();
+ Write_Status("RcvEOT");
+ return(FALSE);
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_RD:
+ if (buffer[0] == STX)
+ {
+ if ((length = buffer[1]) == 0) length = 256;
+ total += length;
+ sprintf(Message, "RcvData %5d bytes received", total);
+ Write_Status(Message);
+
+ if (yappc)
+ {
+ int i;
+ unsigned char checksum = 0;
+
+ for (i = 0; i < length; i++)
+ checksum += buffer[i + 2];
+
+ if (checksum != buffer[length + 2])
+ {
+ Send_CN("Bad Checksum");
+ Write_Status("SndABORT: Bad Checksum");
+ return(FALSE);
+ }
+ }
+
+ write(*filefd, buffer + 2, length);
+ break;
+ }
+
+ if (buffer[0] == ETX && buffer[1] == 0x01)
+ {
+ Send_AF();
+ Write_Status("RcvEof");
+ state = STATE_RH;
+ close(*filefd);
+ *filefd = -1;
+ break;
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+static void yapp_download(int filefd)
+{
+ struct timeval timeval;
+ fd_set sock_read;
+ int n;
+ int buflen = 0;
+ int length;
+ int used;
+ unsigned char buffer[1024];
+
+ Write_Status("RcvWait");
+
+ state = STATE_R;
+ total = 0;
+ yappc = 0;
+
+ while (TRUE)
+ {
+ FD_ZERO(&sock_read);
+ FD_SET(STDIN_FILENO, &sock_read);
+ FD_SET(fd, &sock_read);
+
+ timeval.tv_usec = 0;
+ timeval.tv_sec = TIMEOUT;
+
+ n = select(fd + 1, &sock_read, NULL, NULL, &timeval);
+
+ if (n == -1)
+ {
+ if (!interrupted && errno == EAGAIN)
+ continue;
+ if (!interrupted)
+ perror("select");
+ Send_CN("Internal error");
+ Write_Status("SndABORT");
+ return;
+ }
+
+ if (n == 0) /* Timeout */
+ {
+ Send_CN("Timeout");
+ Write_Status("SndABORT");
+ return;
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &sock_read))
+ {
+ Send_CN("Cancelled by user");
+ Write_Status("SndABORT");
+ return;
+ }
+
+ if (FD_ISSET(fd, &sock_read))
+ {
+ if ((length = read(fd, buffer + buflen, 511)) > 0)
+ {
+ buflen += length;
+
+ do
+ {
+ used = FALSE;
+
+ switch (buffer[0])
+ {
+ case ACK:
+ case ENQ:
+ case ETX:
+ case EOT:
+ if (buflen >= 2)
+ {
+ if (!yapp_download_data(&filefd, buffer))
+ return;
+ buflen -= 2;
+ memcpy(buffer, buffer + 2, buflen);
+ used = TRUE;
+ }
+ break;
+ default:
+ if ((length = buffer[1]) == 0)
+ length = 256;
+ if (buffer[0] == STX)
+ length += yappc;
+ if (buflen >= (length + 2))
+ {
+ if (!yapp_download_data(&filefd, buffer))
+ return;
+ buflen -= length + 2;
+ memcpy(buffer, buffer + length + 2, buflen);
+ used = TRUE;
+ }
+ break;
+ }
+ }
+ while (used);
+ }
+ }
+ }
+}
+
+static int yapp_upload_data(int filefd, char *filename, int filelength, unsigned char *buffer)
+{
+ char Message[80];
+
+ if (buffer[0] == CAN || buffer[0] == NAK)
+ {
+ Write_Status("RcvABORT");
+ return(FALSE);
+ }
+
+ switch (state)
+ {
+ case STATE_S:
+ if (buffer[0] == ACK && buffer[1] == 0x01)
+ {
+ Write_Status("SendHeader");
+ Send_HD(filename, filelength);
+ state = STATE_SH;
+ break;
+ }
+
+ if (buffer[0] == ACK && buffer[1] == 0x02)
+ {
+ sprintf(Message, "SendData %5d bytes transmitted", total);
+ Write_Status(Message);
+ outlen = read(filefd, outbuffer, readlen);
+ outbufptr = 0;
+
+ if (outlen) Send_DT(outlen);
+
+ if (yappc)
+ {
+ outbuffer[outlen] = checksum(outbuffer, outlen);
+ outlen++;
+ }
+
+ state = STATE_SD;
+ break;
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_SH:
+ /* Could get three replies here:
+ * ACK 02 : normal acknowledge.
+ * ACK ACK: yappc acknowledge.
+ * NAK ...: resume request.
+ */
+ if (buffer[0] == NAK && buffer[2] == 'R')
+ {
+ int len;
+ off_t rpos;
+
+ len = buffer[1];
+ if (buffer[len] == 'C') yappc=1;
+ rpos = atol((char *)buffer + 4);
+ lseek(filefd, rpos, SEEK_SET);
+ buffer[0] = ACK;
+ buffer[1] = yappc ? ACK : 0x02;
+ }
+
+ if (buffer[0] == ACK &&
+ (buffer[1] == 0x02 || buffer[1] == ACK))
+ {
+ if (buffer[1] == ACK) yappc = 1;
+
+ sprintf(Message, "SendData %5d bytes transmitted", total);
+ Write_Status(Message);
+ outlen = read(filefd, outbuffer, readlen);
+ outbufptr = 0;
+ if (outlen) Send_DT(outlen);
+ state = STATE_SD;
+
+ if (yappc)
+ {
+ outbuffer[outlen] = checksum(outbuffer, outlen);
+ outlen++;
+ }
+ break;
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_SD:
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_SE:
+ if (buffer[0] == ACK && buffer[1] == 0x03)
+ {
+ Write_Status("SendEOT");
+ Send_ET();
+ state = STATE_ST;
+ break;
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+
+ case STATE_ST:
+ if (buffer[0] == ACK && buffer[1] == 0x04)
+ {
+ return(FALSE);
+ }
+
+ Send_CN("Unknown code");
+ Write_Status("SndABORT");
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+static void yapp_upload(int filefd, char *filename, long filelength)
+{
+ struct timeval timeval;
+ fd_set sock_read;
+ fd_set sock_write;
+ int n;
+ unsigned char buffer[1024];
+ int buflen = 0;
+ int length;
+ int used;
+ char Message[80];
+
+ Write_Status("SendInit");
+
+ readlen = (paclen - 2 > 253) ? 253 : paclen - 2;
+ state = STATE_S;
+ total = 0;
+ yappc = 0;
+
+ Send_SI();
+
+ while (TRUE)
+ {
+ FD_ZERO(&sock_read);
+ FD_ZERO(&sock_write);
+ FD_SET(STDIN_FILENO, &sock_read);
+ FD_SET(fd, &sock_read);
+
+ if (state == STATE_SD)
+ {
+ FD_SET(fd, &sock_write);
+
+ n = select(fd + 1, &sock_read, &sock_write, NULL, NULL);
+ }
+ else
+ {
+ timeval.tv_usec = 0;
+ timeval.tv_sec = TIMEOUT;
+
+ n = select(fd + 1, &sock_read, NULL, NULL, &timeval);
+ }
+
+ if (n == -1)
+ {
+ if (!interrupted && errno == EAGAIN)
+ continue;
+ if (!interrupted)
+ perror("select");
+ Write_Status("SndABORT");
+ Send_CN("Internal error");
+ return;
+ }
+
+ if (n == 0) /* Timeout, not STATE_SD */
+ {
+ Write_Status("SndABORT");
+ Send_CN("Timeout");
+ return;
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &sock_read))
+ {
+ Write_Status("SndABORT");
+ Send_CN("Cancelled by user");
+ return;
+ }
+
+ if (FD_ISSET(fd, &sock_write)) /* Writable, only STATE_SD */
+ {
+ if (outlen > 0)
+ {
+ if ((n = write(fd, outbuffer + outbufptr, outlen)) > 0)
+ {
+ outbufptr += n;
+ outlen -= n;
+ total += n;
+ }
+ }
+
+ if (outlen == 0)
+ {
+ total -= yappc;
+ if ((outlen = read(filefd, outbuffer, readlen)) > 0)
+ {
+ sprintf(Message, "SendData %5d bytes transmitted", total);
+ Write_Status(Message);
+
+ outbufptr = 0;
+ Send_DT(outlen);
+
+ if (yappc)
+ {
+ outbuffer[outlen] = checksum(outbuffer, outlen);
+ outlen++;
+ }
+ }
+ else
+ {
+ Write_Status("SendEof");
+ state = STATE_SE;
+ Send_EF();
+ }
+ }
+ }
+
+ if (FD_ISSET(fd, &sock_read))
+ {
+ if ((length = read(fd, buffer + buflen, 511)) > 0)
+ {
+ buflen += length;
+
+ do
+ {
+ used = FALSE;
+
+ switch (buffer[0])
+ {
+ case ACK:
+ case ENQ:
+ case ETX:
+ case EOT:
+ if (buflen >= 2)
+ {
+ if (!yapp_upload_data(filefd, filename, filelength, buffer))
+ return;
+ buflen -= 2;
+ memcpy(buffer, buffer + 2, buflen);
+ used = TRUE;
+ }
+ break;
+ default:
+ if ((length = buffer[1]) == 0)
+ length = 256;
+ if (buflen >= (length + 2))
+ {
+ if (!yapp_upload_data(filefd, filename, filelength, buffer))
+ return;
+ buflen -= length + 2;
+ memcpy(buffer, buffer + length + 2, buflen);
+ used = TRUE;
+ }
+ break;
+ }
+ }
+ while (used);
+ }
+ }
+ }
+}
+
+void cmd_yapp(char *buf, int bytes)
+{
+ int filefd;
+ long size = 0L;
+ char *t;
+
+ if (bytes == 0) return;
+
+ switch (buf[0])
+ {
+ case 'U':
+ case 'u':
+ if ((t = strchr(buf, '\n')) != NULL)
+ *t = '\0';
+ t = buf + 2;
+ while (*t != '\0' && isspace(*t))
+ t++;
+ if (*t == '\0')
+ {
+ printf("\n[YAPP Upload requires a filename - eg ~yu hello.txt]\n");
+ Send_NR("No filename");
+ return;
+ }
+ if ((filefd = open(t, O_RDONLY)) == -1)
+ {
+ printf("\n[Unable to open upload file]\n");
+ Send_NR("Invalid filename");
+ return;
+ }
+ if (lseek(filefd, 0L, SEEK_END) != -1)
+ size = lseek(filefd, 0L, SEEK_CUR);
+ lseek(filefd, 0L, SEEK_SET);
+ if (size != -1)
+ printf("\n[Uploading %ld bytes from %s using YAPP]\n", size, t);
+ else
+ printf("\n[Uploading from %s using YAPP]\n", t);
+ yapp_upload(filefd, t, size);
+ close(filefd);
+ printf("[Finished YAPP Upload, %d bytes Transmitted]\n", total);
+ break;
+
+ case 'D':
+ case 'd':
+ if ((t = strchr(buf, '\n')) != NULL)
+ *t = '\0';
+ t = buf + 2;
+ while (*t != '\0' && isspace(*t))
+ t++;
+ if (*t == '\0') filefd=-1;
+ else if ((filefd = open(t, O_RDWR | O_APPEND | O_CREAT, 0666)) == -1)
+ {
+ printf("\n[Unable to open %s]\n", buf + 2);
+ Send_NR("Invalid filename");
+ return;
+ }
+ printf("\n[Downloading using YAPP]\n");
+ yapp_download(filefd);
+ close(filefd);
+ printf("[Finished YAPP Download, %d bytes received]\n", total);
+ break;
+
+ default:
+ printf("\nUnknown '~y' escape. Type ~h for a list.\n");
+ break;
+ }
+}
+