summaryrefslogtreecommitdiffstats
path: root/call/call.c
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/call.c
Import ax25-apps 0.0.1 from tarballax25-apps-0.0.1
Diffstat (limited to 'call/call.c')
-rw-r--r--call/call.c1941
1 files changed, 1941 insertions, 0 deletions
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;
+}