From 6dfe32758e1a995b1241af8c981798c22cd70439 Mon Sep 17 00:00:00 2001 From: Dave Hibberd Date: Fri, 30 Aug 2024 10:14:56 +0100 Subject: [PATCH] New upstream version 6.0.24.42 --- 6pack.c | 2129 ++++++++ ARDOP.c | 12 + BBSUtilities.c | 456 +- BPQChat.vcproj.NOTTSDESKTOP.John.user | 65 + BPQMail.c | 1 + BPQMail.vcproj.NOTTSDESKTOP.John.user | 65 + BPQMail.vcproj.SKIGACER.johnw.user | 65 + BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user | 65 + BPQWinAPP.vcproj.NOTTSDESKTOP.John.user | 65 + Bpq32.c | 7 + CBPQ32.vcproj | 6 +- CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user | 65 + CBPQ32.vcproj.NOTTSDESKTOP.John.user | 65 + CBPQ32.vcproj.SKIGACER.johnw.user | 65 + CommonCode.c | 16 +- HFCommon.c | 2 + HTTPcode.c | 19 +- LinBPQ.c | 323 +- MHSave.txt | 0 MailNode.vcproj.NOTTSDESKTOP.John.user | 65 + MailNode.vcproj.SKIGACER.johnw.user | 65 + Moncode.c | 7 +- SCSPactor.c.bak | 4322 ----------------- SerialPort.c | 3 +- TelnetV6.c | 1 + VARA.c | 2 +- Versions.h | 6 +- WinRPRHelper.vcproj.NOTTSDESKTOP.John.user | 65 + ...rControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user | 65 + WinmorControl.vcproj.NOTTSDESKTOP.John.user | 65 + bpqchat.c | 3 +- bpqmail.h | 3 +- tncinfo.h | 11 +- upnp.c | 9 + 34 files changed, 3429 insertions(+), 4754 deletions(-) create mode 100644 6pack.c create mode 100644 BPQChat.vcproj.NOTTSDESKTOP.John.user create mode 100644 BPQMail.vcproj.NOTTSDESKTOP.John.user create mode 100644 BPQMail.vcproj.SKIGACER.johnw.user create mode 100644 BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user create mode 100644 BPQWinAPP.vcproj.NOTTSDESKTOP.John.user create mode 100644 CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user create mode 100644 CBPQ32.vcproj.NOTTSDESKTOP.John.user create mode 100644 CBPQ32.vcproj.SKIGACER.johnw.user create mode 100644 MHSave.txt create mode 100644 MailNode.vcproj.NOTTSDESKTOP.John.user create mode 100644 MailNode.vcproj.SKIGACER.johnw.user delete mode 100644 SCSPactor.c.bak create mode 100644 WinRPRHelper.vcproj.NOTTSDESKTOP.John.user create mode 100644 WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user create mode 100644 WinmorControl.vcproj.NOTTSDESKTOP.John.user diff --git a/6pack.c b/6pack.c new file mode 100644 index 0000000..ba7bd07 --- /dev/null +++ b/6pack.c @@ -0,0 +1,2129 @@ +/* +Copyright 2001-2022 John Wiseman G8BPQ + +This file is part of LinBPQ/BPQ32. + +LinBPQ/BPQ32 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 3 of the License, or +(at your option) any later version. + +LinBPQ/BPQ32 is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses +*/ + +/* + +Using code from 6pack Linux Kernel driver with the following licence and credits + + * 6pack driver version 0.4.2, 1999/08/22 + * + * This module: + * This module 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. + * + * This module implements the AX.25 protocol for kernel-based + * devices like TTYs. It interfaces between a raw TTY, and the + * kernel's AX.25 protocol layers, just like slip.c. + * AX.25 needs to be separated from slip.c while slip.c is no + * longer a static kernel device since it is a module. + * + * Author: Andreas Könsgen + * + * Lots of stuff has been taken from mkiss.c, written by + * Hans Alblas + * + * with the fixes from + * + * Jonathan (G4KLX) Fixed to match Linux networking changes - 2.1.15. + * Matthias (DG2FEF) Fixed bug in ax25_close(): dev_lock_wait() was + * called twice, causing a deadlock. + */ + + +// 6pack needs fast response to received characters, and I want to be able to operate over TCP links as well as serial. +// So I think the character level stuff may need to run in a separate thread, probably using select. +// +// I also need to support multiple 6pack ports. + +// ?? Do we add this as a backend to KISS driver or a separate Driver. KISS Driver is already quite messy. Not decided yet. + +// ?? If using serial/real TNC we need to be able to interleave control and data bytes, but I think with TCP/QtSM it won't be necessary +// ?? Also a don't see any point in running multiple copies of QtSM on one port, but maybe should treat the QtSM channels as +// multidropped ports for scheduling (?? only if on same radio ??) + +// ?? I think it needs to look like a KISS (L2) driver but will need a transmit scheduler level to do DCD/CSMA/PTT processing, +// ideally with an interlock to other drivers on same port. This needs some thought with QtSM KISS with multiple modems on one channel + + + + + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + +#define _CRT_SECURE_NO_DEPRECATE + +#include "compatbits.h" +#include +#include "CHeaders.h" + +#include "bpq32.h" + +#include "tncinfo.h" + +#ifndef WIN32 + +#define APIENTRY +#define DllExport +#define VOID void + +#else +#include +#endif + +/**************************************************************************** + * Defines for the 6pack driver. + ****************************************************************************/ + +/* + provisoric define +*/ +#define SIXP_MAJOR MKISS_MAJOR +/* end of provisoric defines */ + + +#define TRUE 1 +#define FALSE 0 + +#define AX25_MAXDEV 16 /* MAX number of AX25 channels; + This can be overridden with + insmod -oax25_maxdev=nnn */ +#define AX_MTU 236 + +/* 6pack protocol bytes/masks. */ +#define SIXP_INIT_CMD 0xE8 +#define SIXP_TNC_FOUND 0xE9 +#define SIXP_CMD_MASK 0xC0 +#define SIXP_PRIO_CMD_MASK 0x80 +#define SIXP_PRIO_DATA_MASK 0x38 +#define SIXP_STD_CMD_MASK 0x40 +#define SIXP_DCD_MASK 0x08 +#define SIXP_RX_DCD_MASK 0x18 +#define SIXP_CHN_MASK 0x07 +#define SIXP_TX_MASK 0x20 +#define SIXP_CON_LED_ON 0x68 +#define SIXP_STA_LED_ON 0x70 +#define SIXP_LED_OFF 0x60 + +/* checksum for a valid 6pack encapsulated packet */ +#define SIXP_CHKSUM 0xFF + +/* priority commands */ +#define SIXP_SEOF 0x40 /* TX underrun */ +#define SIXP_TX_URUN 0x48 /* TX underrun */ +#define SIXP_RX_ORUN 0x50 /* RX overrun */ +#define SIXP_RX_BUF_OVL 0x58 /* RX overrun */ + +struct sixPackTNCInfo +{ + // info for each TNC in chain + + int magic; + + char * name; + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + int rcount; /* received chars counter */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *xhead; /* pointer to next byte to XMIT */ + int xleft; /* bytes left in XMIT queue */ + + /* SLIP interface statistics. */ + unsigned long rx_packets; /* inbound frames counter */ + unsigned long tx_packets; /* outbound frames counter */ + unsigned long rx_errors; /* Parity, etc. errors */ + unsigned long tx_errors; /* Planned stuff */ + unsigned long rx_dropped; /* No memory for skb */ + unsigned long tx_dropped; /* When MTU change */ + unsigned long rx_over_errors; /* Frame bigger then SLIP buf. */ + + /* Detailed SLIP statistics. */ + int mtu; /* Our mtu (to spot changes!) */ + int buffsize; /* Max buffers sizes */ + + + unsigned char flags; /* Flag values/ mode etc */ +#define AXF_INUSE 0 /* Channel in use */ +#define AXF_ESCAPE 1 /* ESC received */ +#define AXF_ERROR 2 /* Parity, etc. error */ +#define AXF_KEEPTEST 3 /* Keepalive test flag */ +#define AXF_OUTWAIT 4 /* is outpacket was flag */ + + int mode; + + + /* variables for the state machine */ + + unsigned char tnc_ok; + unsigned char status; + unsigned char status1; + unsigned char status2; + + unsigned char duplex; + unsigned char led_state; + unsigned char tx_enable; + + unsigned char raw_buf[4]; /* receive buffer */ + unsigned char cooked_buf[400]; /* receive buffer after 6pack decoding */ + + unsigned int rx_count; /* counter for receive buffer */ + unsigned int rx_count_cooked; /* counter for receive buffer after 6pack decoding */ + + unsigned char tx_delay; + unsigned char persistance; + unsigned char slottime; + +}; + + +struct sixPackPortInfo +{ + // Per port (chain of TNC's) + + unsigned int linkOK; // Set if response is received + unsigned int reinitTimer; + + struct sixPackTNCInfo * TNCS[8]; // Max TNCs in chain Not sure if real 6pack uses o or 1 for first +}; + + +#define AX25_MAGIC 0x5316 +#define SIXP_DRIVER_MAGIC 0x5304 + +#define SIXP_INIT_RESYNC_TIMEOUT 150 /* in 10 ms */ +#define SIXP_RESYNC_TIMEOUT 500 /* in 10 ms */ + +/* default radio channel access parameters */ +#define SIXP_TXDELAY 25 /* in 10 ms */ +#define SIXP_PERSIST 50 +#define SIXP_SLOTTIME 10 /* in 10 ms */ + +static int sixpack_encaps(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay); +static void sixpack_decaps(struct sixPackPortInfo *, unsigned char); + +static void decode_prio_command(unsigned char, struct sixPackTNCInfo *); +static void decode_std_command(unsigned char, struct sixPackTNCInfo *); +static void decode_data(unsigned char, struct sixPackTNCInfo *); +static void resync_tnc(unsigned long); +static void xmit_on_air(struct sixPackTNCInfo *ax); +static void start_tx_timer(struct sixPackTNCInfo *ax); +int Connectto6Pack(int port); + +VOID __cdecl Debugprintf(const char * format, ...); + +/* Set the "sending" flag. This must be atomic, hence the ASM. */ + +static void ax_lock(struct sixPackTNCInfo *ax) +{ +// if (test_and_set_bit(0, (void *)&ax->dev->tbusy)) +// printk(KERN_ERR "6pack: %s: trying to lock already locked device!\n", ax->dev->name); +} + + +/* Clear the "sending" flag. This must be atomic, hence the ASM. */ +static void ax_unlock(struct sixPackTNCInfo *ax) +{ +// if (!test_and_clear_bit(0, (void *)&ax->dev->tbusy)) +// printk(KERN_ERR "6pack: %s: trying to unlock already unlocked device!\n", ax->dev->name); +} +/* Send one completely decapsulated AX.25 packet to the AX.25 layer. */ +static void ax_bump(struct sixPackTNCInfo *ax) +{ +} + +VOID SixPackProcessReceivedPacket(struct TNCINFO * TNC) +{ + int InputLen, MsgLen; + unsigned char * ptr; + char Buffer[4096]; + + if (TNC->InputLen > 8000) // Shouldnt have packets longer than this + TNC->InputLen=0; + + InputLen = recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0); + + if (InputLen == 0 || InputLen == SOCKET_ERROR) + { + // Does this mean closed? + + int err = GetLastError(); + + closesocket(TNC->TCPSock); + + TNC->TCPSock = 0; + + TNC->CONNECTED = FALSE; + TNC->Streams[0].ReportDISC = TRUE; + + sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); + MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + + return; + } + + TNC->InputLen += InputLen; + + // Process Bytes + +} + + + +static int sixpack_encaps(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay) +{ + int count = 0; + unsigned char checksum = 0, buf[400]; + int raw_count = 0; + + tx_buf_raw[raw_count++] = SIXP_PRIO_CMD_MASK | SIXP_TX_MASK; + tx_buf_raw[raw_count++] = SIXP_SEOF; + + buf[0] = tx_delay; + for(count = 1; count < length; count++) + buf[count] = tx_buf[count]; + + for(count = 0; count < length; count++) + checksum += buf[count]; + buf[length] = (unsigned char)0xff - checksum; + + for(count = 0; count <= length; count++) { + if((count % 3) == 0) { + tx_buf_raw[raw_count++] = (buf[count] & 0x3f); + tx_buf_raw[raw_count] = ((buf[count] >> 2) & 0x30); + } + else if((count % 3) == 1) { + tx_buf_raw[raw_count++] |= (buf[count] & 0x0f); + tx_buf_raw[raw_count] = + ((buf[count] >> 2) & 0x3c); + } else { + tx_buf_raw[raw_count++] |= (buf[count] & 0x03); + tx_buf_raw[raw_count++] = + (buf[count] >> 2); + } /* else */ + } /* for */ + if ((length % 3) != 2) + raw_count++; + tx_buf_raw[raw_count++] = SIXP_SEOF; + return(raw_count); +} + + +static void sixpack_decaps(struct sixPackPortInfo *ax, unsigned char inbyte) +{ + // if (inbyte == SIXP_TNC_FOUND) { + // This is wrong. It will only work with one TNC in the chain. Should look for E8 in top bits. Bottome 3 bits are number in chain + + if ((inbyte & SIXP_INIT_CMD) == 0) + { + int Count = inbyte & SIXP_CHN_MASK; + struct sixPackTNCInfo * sixTNC; + + int i; + + Debugprintf("6pack: %d TNCs found. ", Count); + + // clear existing TNC strucs and allocate new ones if needed + + for (i = 0; i < Count; i++) + { + sixTNC = ax->TNCS[i]; + + if (sixTNC) + memset(sixTNC, 0, sizeof(struct sixPackTNCInfo)); + else + sixTNC = ax->TNCS[i] = zalloc(sizeof(struct sixPackTNCInfo)); + + sixTNC->tnc_ok = 1; + } + + ax->linkOK = TRUE; + + } +/* +if((inbyte & SIXP_PRIO_CMD_MASK) != 0) + decode_prio_command(inbyte, ax); + else if((inbyte & SIXP_STD_CMD_MASK) != 0) + decode_std_command(inbyte, ax); + else { + if ((ax->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK) + decode_data(inbyte, ax); + } +*/ +} + +/* identify and execute a 6pack priority command byte */ + +void decode_prio_command(unsigned char cmd, struct sixPackTNCInfo *ax) +{ + unsigned char channel; + + channel = cmd & SIXP_CHN_MASK; + if ((cmd & SIXP_PRIO_DATA_MASK) != 0) { /* idle ? */ + + /* RX and DCD flags can only be set in the same prio command, + if the DCD flag has been set without the RX flag in the previous + prio command. If DCD has not been set before, something in the + transmission has gone wrong. In this case, RX and DCD are + cleared in order to prevent the decode_data routine from + reading further data that might be corrupt. */ + + if (((ax->status & SIXP_DCD_MASK) == 0) && + ((cmd & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)) { + if (ax->status != 1) + Debugprintf("6pack: protocol violation\n"); + else + ax->status = 0; + cmd &= !SIXP_RX_DCD_MASK; + } + ax->status = cmd & SIXP_PRIO_DATA_MASK; + } /* if */ + + + /* if the state byte has been received, the TNC is present, + so the resync timer can be reset. */ + + if (ax->tnc_ok == 1) { +// del_timer(&(ax->resync_t)); +// ax->resync_t.data = (unsigned long) ax; +// ax->resync_t.function = resync_tnc; +// ax->resync_t.expires = jiffies + SIXP_INIT_RESYNC_TIMEOUT; +// add_timer(&(ax->resync_t)); + } + + ax->status1 = cmd & SIXP_PRIO_DATA_MASK; +} + +/* try to resync the TNC. Called by the resync timer defined in + decode_prio_command */ + +static void resync_tnc(unsigned long channel) +{ + static char resync_cmd = SIXP_INIT_CMD; + struct sixPackTNCInfo *ax = (struct sixPackTNCInfo *) channel; + + Debugprintf("6pack: resyncing TNC\n"); + + /* clear any data that might have been received */ + + ax->rx_count = 0; + ax->rx_count_cooked = 0; + + /* reset state machine */ + + ax->status = 1; + ax->status1 = 1; + ax->status2 = 0; + ax->tnc_ok = 0; + + /* resync the TNC */ + + ax->led_state = SIXP_LED_OFF; +// ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); +// ax->tty->driver.write(ax->tty, 0, &resync_cmd, 1); + + + /* Start resync timer again -- the TNC might be still absent */ + +// del_timer(&(ax->resync_t)); +// ax->resync_t.data = (unsigned long) ax; +// ax->resync_t.function = resync_tnc; +// ax->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT; +// add_timer(&(ax->resync_t)); +} + + + +/* identify and execute a standard 6pack command byte */ + +void decode_std_command(unsigned char cmd, struct sixPackTNCInfo *ax) +{ + unsigned char checksum = 0, channel; + unsigned int i; + + channel = cmd & SIXP_CHN_MASK; + switch(cmd & SIXP_CMD_MASK) { /* normal command */ + case SIXP_SEOF: + if ((ax->rx_count == 0) && (ax->rx_count_cooked == 0)) { + if ((ax->status & SIXP_RX_DCD_MASK) == + SIXP_RX_DCD_MASK) { + ax->led_state = SIXP_CON_LED_ON; +// ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); + } /* if */ + } else { + ax->led_state = SIXP_LED_OFF; +// ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); + /* fill trailing bytes with zeroes */ + if (ax->rx_count == 2) { + decode_data(0, ax); + decode_data(0, ax); + ax->rx_count_cooked -= 2; + } + else if (ax->rx_count == 3) { + decode_data(0, ax); + ax->rx_count_cooked -= 1; + } + for (i=0; i< ax->rx_count_cooked; i++) + checksum += ax->cooked_buf[i]; + if (checksum != SIXP_CHKSUM) { + Debugprintf("6pack: bad checksum %2.2x\n", checksum); + } else { + ax->rcount = ax->rx_count_cooked-1; + ax_bump(ax); + } /* else */ + ax->rx_count_cooked = 0; + } /* else */ + break; + case SIXP_TX_URUN: + Debugprintf("6pack: TX underrun\n"); + break; + case SIXP_RX_ORUN: + Debugprintf("6pack: RX overrun\n"); + break; + case SIXP_RX_BUF_OVL: + Debugprintf("6pack: RX buffer overflow\n"); + } /* switch */ +} /* function */ + +/* decode 4 sixpack-encoded bytes into 3 data bytes */ + +void decode_data(unsigned char inbyte, struct sixPackTNCInfo *ax) +{ + + unsigned char *buf; + + if (ax->rx_count != 3) + ax->raw_buf[ax->rx_count++] = inbyte; + else { + buf = ax->raw_buf; + ax->cooked_buf[ax->rx_count_cooked++] = + buf[0] | ((buf[1] << 2) & 0xc0); + ax->cooked_buf[ax->rx_count_cooked++] = + (buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0); + ax->cooked_buf[ax->rx_count_cooked++] = + (buf[2] & 0x03) | (inbyte << 2); + ax->rx_count = 0; + } +} + +// This takes a packet from the KISS driver and converts to 6pack format + +static void ax_encaps(struct sixPackTNCInfo *ax, unsigned char *icp, int len) +{ + unsigned char *p; + int count; + struct sixPackTNCInfo *tmp_ax; + + if (len > ax->mtu) { /* Sigh, shouldn't occur BUT ... */ + len = ax->mtu; + Debugprintf("6pack: %s: truncating oversized transmit packet!\n", ax->name); + ax->tx_dropped++; + ax_unlock(ax); + return; + } + + p = icp; + + if (p[0] > 5) + { + Debugprintf("%s: invalid KISS command -- dropped\n", ax->name); + ax_unlock(ax); + return; + } + + if ((p[0] != 0) && (len > 2)) + { + Debugprintf("%s: KISS command packet too long -- dropped\n", ax->name); + ax_unlock(ax); + return; + } + + if ((p[0] == 0) && (len < 15)) + { + Debugprintf("%s: bad AX.25 packet to transmit -- dropped\n", ax->name); + ax->tx_dropped++; + ax_unlock(ax); + return; + } + + switch(p[0]) + { + case 1: tmp_ax->tx_delay = p[1]; break; + case 2: tmp_ax->persistance = p[1]; break; + case 3: tmp_ax->slottime = p[1]; break; + case 4: Debugprintf("6pack: got KISS command 4 -- ignored\n"); + break; + case 5: tmp_ax->duplex = p[1]; break; + } + + // How do we handle ACKMODE ?? + + if (p[0] != 0) { + ax_unlock(ax); + return; + } + + count = sixpack_encaps(p, (unsigned char *) tmp_ax->xbuff, len, tmp_ax->tx_delay); + tmp_ax->xleft = count; + tmp_ax->status2 = count; + tmp_ax->xhead = tmp_ax->xbuff; + + /* in case of DAMA or fullduplex operation, we don't take care + about the state of the DCD or of any timers, as the determination + of the correct time to send is the job of the AX.25 layer. We send + immediately after data has arrived. */ + + if (tmp_ax->duplex == 1) { /* DAMA / fullduplex */ + xmit_on_air(tmp_ax); + } else { /* CSMA */ + start_tx_timer(tmp_ax); + } /* if ax->duplex */ +} /* ax_encaps */ + +// This starts sending a packet to a TNC. TNC will immediately send (after TXD) + +/* the next two functions perform the persistence/slottime algorithm for CSMA access. + If the persistence check was successful, write the data to the serial driver. + Note that in case of DAMA operation, the data is not sent here. */ + +/* set timer to time out slottime */ +static void start_tx_timer(struct sixPackTNCInfo *ax) +{ +// del_timer(&(ax->tx_t)); +// ax->tx_t.data = (unsigned long) ax; +// ax->tx_t.function = tx_schedule; +// ax->tx_t.expires = jiffies + (((ax->slottime)+1)*HZ)/100; +// add_timer(&(ax->tx_t)); +} + +/* compute random number and check if it is ok to send */ +static void tx_schedule(unsigned long channel) +{ + struct sixPackTNCInfo *ax = (struct sixPackTNCInfo *) channel; + static unsigned char random; + + random = random * 17 + 41; + + if (((ax->status1 & SIXP_DCD_MASK) == 0) && (random < ax->persistance)) + xmit_on_air(ax); + else + start_tx_timer(ax); +} + + +static void xmit_on_air(struct sixPackTNCInfo *ax) +{ + int actual; + +// ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + ax->led_state = SIXP_STA_LED_ON; +// ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); + ax->tx_enable = 1; +// actual = ax->tty->driver.write(ax->tty, 0, ax->xbuff, ax->status2); + ax->tx_packets++; +// ax->dev->trans_start = jiffies; + ax->xleft -= actual; + ax->xhead = ax->xbuff + actual; + ax->led_state = SIXP_LED_OFF; +// ax->tty->driver.write(ax->tty, 0, &(ax->led_state), 1); +} /* xmit_on_air */ + + +// BPQ Driver Module Interface + + +extern int (WINAPI FAR *GetModuleFileNameExPtr)(); +extern int (WINAPI FAR *EnumProcessesPtr)(); + +static int Socket_Data(int sock, int error, int eventcode); + +VOID MoveWindows(struct TNCINFO * TNC); +static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen); +int ReadCOMBlockEx(HANDLE fd, char * Block, int MaxLength, BOOL * Error); +BOOL SerialWriteCommBlock(struct TNCINFO * TNC); +void SerialCheckRX(struct TNCINFO * TNC); +int SerialSendData(struct TNCINFO * TNC, UCHAR * data, int txlen); +int SerialSendCommand(struct TNCINFO * TNC, UCHAR * data); +int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); +VOID SendInitScript(struct TNCINFO * TNC); +int SIXPACKGetLine(char * buf); +int ProcessEscape(UCHAR * TXMsg); +VOID SIXPACKProcessReceivedPacket(struct TNCINFO * TNC); +static int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); +int ConnecttoKISS(int port); +TRANSPORTENTRY * SetupNewSession(TRANSPORTENTRY * Session, char * Bufferptr); +BOOL DecodeCallString(char * Calls, BOOL * Stay, BOOL * Spy, UCHAR * AXCalls); +BOOL FindLink(UCHAR * LinkCall, UCHAR * OurCall, int Port, struct _LINKTABLE ** REQLINK); +VOID RESET2(struct _LINKTABLE * LINK); +VOID L2SENDXID(struct _LINKTABLE * LINK); +VOID SENDSABM(struct _LINKTABLE * LINK); + +static char ClassName[]="KISSSTATUS"; +static char WindowTitle[] = "SIXPACK"; +static int RigControlRow = 165; + +#ifndef LINBPQ +#include +#endif + +extern int SemHeldByAPI; + +static RECT Rect; + +static int ProcessLine(char * buf, int Port); + +VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); + +#define FEND 0xC0 // KISS CONTROL CODES +#define FESC 0xDB +#define TFEND 0xDC +#define TFESC 0xDD + +static int ProcessLine(char * buf, int Port) +{ + UCHAR * ptr,* p_cmd; + char * p_ipad = 0; + char * p_port = 0; + unsigned short WINMORport = 0; + int BPQport; + int len=510; + struct TNCINFO * TNC; + char errbuf[256]; + + strcpy(errbuf, buf); + + ptr = strtok(buf, " \t\n\r"); + + if(ptr == NULL) return (TRUE); + + if(*ptr =='#') return (TRUE); // comment + + if(*ptr ==';') return (TRUE); // comment + + if (_stricmp(buf, "ADDR")) + return FALSE; // Must start with ADDR + + ptr = strtok(NULL, " \t\n\r"); + + BPQport = Port; + p_ipad = ptr; + + TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO)); + memset(TNC, 0, sizeof(struct TNCINFO)); + + TNC->DefaultMode = TNC->WL2KMode = 0; // Packet 1200 + + TNC->InitScript = malloc(1000); + TNC->InitScript[0] = 0; + + if (p_ipad == NULL) + p_ipad = strtok(NULL, " \t\n\r"); + + if (p_ipad == NULL) return (FALSE); + + p_port = strtok(NULL, " \t\n\r"); + + if (p_port == NULL) return (FALSE); + + WINMORport = atoi(p_port); + + TNC->destaddr.sin_family = AF_INET; + TNC->destaddr.sin_port = htons(WINMORport); + + TNC->HostName = malloc(strlen(p_ipad)+1); + + if (TNC->HostName == NULL) return TRUE; + + strcpy(TNC->HostName,p_ipad); + + ptr = strtok(NULL, " \t\n\r"); + + if (ptr) + { + if (_stricmp(ptr, "PTT") == 0) + { + ptr = strtok(NULL, " \t\n\r"); + + if (ptr) + { + DecodePTTString(TNC, ptr); + ptr = strtok(NULL, " \t\n\r"); + } + } + } + + if (ptr) + { + if (_memicmp(ptr, "PATH", 4) == 0) + { + p_cmd = strtok(NULL, "\n\r"); + if (p_cmd) TNC->ProgramPath = _strdup(p_cmd); + } + } + + // Read Initialisation lines + + while (TRUE) + { + if (GetLine(buf) == 0) + return TRUE; + + strcpy(errbuf, buf); + + if (memcmp(buf, "****", 4) == 0) + return TRUE; + + ptr = strchr(buf, ';'); + if (ptr) + { + *ptr++ = 13; + *ptr = 0; + } + + if (_memicmp(buf, "UPDATEMAP", 9) == 0) + TNC->PktUpdateMap = TRUE; + else if (standardParams(TNC, buf) == FALSE) + strcat(TNC->InitScript, buf); + } + return (TRUE); +} + +char * Config; +static char * ptr1, * ptr2; + +int SIXPACKGetLine(char * buf) +{ +loop: + + if (ptr2 == NULL) + return 0; + + memcpy(buf, ptr1, ptr2 - ptr1 + 2); + buf[ptr2 - ptr1 + 2] = 0; + ptr1 = ptr2 + 2; + ptr2 = strchr(ptr1, 13); + + if (buf[0] < 0x20) goto loop; + if (buf[0] == '#') goto loop; + if (buf[0] == ';') goto loop; + + if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; + if (buf[strlen(buf)-1] < 0x20) buf[strlen(buf)-1] = 0; + buf[strlen(buf)] = 13; + + return 1; +} + +VOID SuspendOtherPorts(struct TNCINFO * ThisTNC); +VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC); +VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); + +static time_t ltime; + +static VOID SendToTNC(struct TNCINFO * TNC, int Stream, UCHAR * Encoded, int EncLen) +{ + if (TNC->hDevice) + { + // Serial mode. Queue to Hostmode driver + + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + if (buffptr == 0) return; // No buffers, so ignore + + buffptr->Len = EncLen; + memcpy(&buffptr->Data[0], Encoded, EncLen); + + C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); + TNC->Streams[Stream].FramesQueued++; + + return; + } +} + + +static SOCKADDR_IN sinx; +static SOCKADDR_IN rxaddr; + +static int addrlen=sizeof(sinx); + + +static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) +{ + int datalen; + PMSGWITHLEN buffptr; + char txbuff[500]; + unsigned int bytes,txlen = 0; + UCHAR * TXMsg; + + size_t Param; + int Stream = 0; + HKEY hKey=0; + struct TNCINFO * TNC = TNCInfo[port]; + struct STREAMINFO * STREAM = &TNC->Streams[0]; + struct ScanEntry * Scan; + + if (TNC == NULL) + return 0; // Port not defined + + if (TNC->CONNECTED == 0 && TNC->CONNECTING == 0) + { + // Try to reopen every 30 secs + + if (fn > 3 && fn < 7) + goto ok; + + TNC->ReopenTimer++; + + if (TNC->ReopenTimer < 150) + return 0; + + TNC->ReopenTimer = 0; + + Connectto6Pack(TNC->Port); + + return 0; + + SendInitScript(TNC); + + } +ok: + + switch (fn) + { + case 7: + + // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances + + SerialCheckRX(TNC); + return 0; + + case 1: // poll + + STREAM = &TNC->Streams[0]; + + if (STREAM->NeedDisc) + { + STREAM->NeedDisc--; + + if (STREAM->NeedDisc == 0) + { + // Send the DISCONNECT + + SerialSendCommand(TNC, "DISCONNECT\r"); + } + } + + if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0) + { + // New Attach + + int calllen; + char Msg[80]; + + STREAM->Attached = TRUE; + + calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall); + TNC->Streams[Stream].MyCall[calllen] = 0; + + + // Stop other ports in same group + + SuspendOtherPorts(TNC); + + sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall); + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + + // Stop Scanning + + sprintf(Msg, "%d SCANSTOP", TNC->Port); + + Rig_Command( (TRANSPORTENTRY *) -1, Msg); + } + + if (STREAM->Attached) + CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); + + // See if any frames for this port + + STREAM = &TNC->Streams[0]; + + if (STREAM->BPQtoPACTOR_Q) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)Q_REM(&STREAM->BPQtoPACTOR_Q); + UCHAR * data = &buffptr->Data[0]; + STREAM->FramesQueued--; + txlen = (int)buffptr->Len; + STREAM->BytesTXed += txlen; + + bytes=SerialSendData(TNC, data, txlen); + WritetoTrace(TNC, data, txlen); + } + + if (STREAM->PACTORtoBPQ_Q != 0) + { + buffptr = (PMSGWITHLEN)Q_REM(&STREAM->PACTORtoBPQ_Q); + + datalen = (int)buffptr->Len; + + buff->PORT = Stream; // Compatibility with Kam Driver + buff->PID = 0xf0; + memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte + datalen += sizeof(void *) + 4; + + PutLengthinBuffer(buff, datalen); + + ReleaseBuffer(buffptr); + + return (1); + } + + if (STREAM->ReportDISC) // May need a delay so treat as a counter + { + STREAM->ReportDISC--; + + if (STREAM->ReportDISC == 0) + { + buff->PORT = Stream; + return -1; + } + } + + return (0); + + case 2: // send + + Stream = 0; + + if (!TNC->CONNECTED) + return 0; // Don't try if not connected + + STREAM = &TNC->Streams[0]; + + if (TNC->SwallowSignon) + { + TNC->SwallowSignon = FALSE; // Discard *** connected + return 0; + } + + // We may get KISS packets (UI or session related) or text commands such as RADIO, CONNECT + + txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN); + + TXMsg = &buff->L2DATA[0]; + + if (buff->PID != 240) // ax.25 address + { + txlen = KissEncode(&buff->PID, txbuff, txlen); + txlen = send(TNC->TCPSock, txbuff, txlen, 0); + return 1; + } + + TXMsg[txlen - 1] = 0; + strcpy(txbuff, TXMsg); + + if (STREAM->Attached == 0) + return 0; + + if (STREAM->Connected) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + if (buffptr == 0) return 1; // No buffers, so ignore + + buffptr->Len = txlen; + memcpy((UCHAR *)&buffptr->Data[0], &buff->L2DATA[0], txlen); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + + // connected data + + return 1; + } + + // Process as Text Command + + if (_memicmp(txbuff, "D\r", 2) == 0 || _memicmp(txbuff, "BYE\r", 4) == 0) + { + STREAM->ReportDISC = TRUE; // Tell Node + return 0; + } + + if (_memicmp(txbuff, "RADIO ", 6) == 0) + { + sprintf(&buff->L2DATA[0], "%d %s", TNC->Port, &txbuff[6]); + + if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &buff->L2DATA[0])) + { + } + else + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + if (buffptr == 0) return 1; // No buffers, so ignore + + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "%s", &buff->L2DATA[0]); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + } + return 1; + } + + + if (_memicmp(txbuff, "OVERRIDEBUSY", 12) == 0) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + TNC->OverrideBusy = TRUE; + + if (buffptr) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} OK\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + } + + return 0; + + } + + if (_memicmp(&buff->L2DATA[0], "SessionTimeLimit", 16) == 0) + { + if (buff->L2DATA[16] != 13) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + + TNC->SessionTimeLimit = atoi(&buff->L2DATA[16]) * 60; + + if (buffptr) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} OK\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + } + return 0; + } + } + + if (toupper(buff->L2DATA[0]) == 'C' && buff->L2DATA[1] == ' ' && txlen > 2) // Connect + { + // Connect Command. Pass to L2 code to start session + + char * ptr = strchr(&buff->L2DATA[2], 13); + TRANSPORTENTRY * NewSess = L4TABLE; + struct _LINKTABLE * LINK; + TRANSPORTENTRY * Session = TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK; + struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL; + + UCHAR axcalls[64]; + UCHAR ourcall[7]; // Call we are using (may have SSID bits inverted + int Stay = 0, Spy = 0, CQFLAG = 0, n; + + if (ptr) + *ptr = 0; + + _strupr(&buff->L2DATA[2]); + + if (DecodeCallString(&buff->L2DATA[2], &Stay, &Spy, &axcalls[0]) == 0) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} Invalid Call\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + } + return 0; + } + + // Code copied from cmdc00 + + // Get Session Entry for Downlink + + NewSess = SetupNewSession(Session, NULL); + + if (NewSess == NULL) + return 0; + + NewSess->L4CIRCUITTYPE = L2LINK + DOWNLINK; + + // FORMAT LINK TABLE ENTRY FOR THIS CONNECTION + + memcpy(Session->L4USER, NewSess->L4USER, 7); + memcpy(ourcall, NewSess->L4USER, 7); + + // SSID SWAP TEST - LEAVE ALONE FOR HOST or Pactor like (unless UZ7HO) + + if ((Session->L4CIRCUITTYPE & BPQHOST))// host + goto noFlip3; + + if ((Session->L4CIRCUITTYPE & PACTOR)) + { + // incoming is Pactorlike - see if UZ7HO + + if (memcmp(Session->L4TARGET.EXTPORT->PORT_DLL_NAME, "UZ7HO", 5) != 0) + goto noFlip3; + + if (Session->L4TARGET.EXTPORT->MAXHOSTMODESESSIONS < 2) // Not multisession + goto noFlip3; + + ourcall[6] ^= 0x1e; // UZ7HO Uplink - flip + } + else + + // Must be L2 uplink - flip + + ourcall[6] ^= 0x1e; // Flip SSID + +noFlip3: + + // SET UP NEW SESSION (OR RESET EXISTING ONE) + + FindLink(axcalls, ourcall, TNC->Port, &LINK); + + if (LINK == NULL) + { + PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); + if (buffptr) + { + buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SIXPACK} Sorry - System Tables Full\r"); + C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); + } + return 0; + } + + memcpy(LINK->LINKCALL, axcalls, 7); + memcpy(LINK->OURCALL, ourcall, 7); + + LINK->LINKPORT = PORT; + + LINK->L2TIME = PORT->PORTT1; + + // Copy Digis + + n = 7; + ptr = &LINK->DIGIS[0]; + + while (axcalls[n]) + { + memcpy(ptr, &axcalls[n], 7); + n += 7; + ptr += 7; + + LINK->L2TIME += 2 * PORT->PORTT1; // ADJUST TIMER VALUE FOR 1 DIGI + } + + LINK->LINKTYPE = 2; // DOWNLINK + LINK->LINKWINDOW = PORT->PORTWINDOW; + + RESET2(LINK); // RESET ALL FLAGS + +// if (CMD->String[0] == 'N' && SUPPORT2point2) +// LINK->L2STATE = 1; // New (2.2) send XID +// else + LINK->L2STATE = 2; // Send SABM + + LINK->CIRCUITPOINTER = NewSess; + + NewSess->L4TARGET.LINK = LINK; + + if (PORT->PORTPACLEN) + NewSess->SESSPACLEN = Session->SESSPACLEN = PORT->PORTPACLEN; + + STREAM->Connecting = TRUE; + + if (CQFLAG == 0) // if a CQ CALL DONT SEND SABM + { + if (LINK->L2STATE == 1) + L2SENDXID(LINK); + else + SENDSABM(LINK); + } + return 0; + } + + return 0; + + case 3: + + // CHECK IF OK TO SEND (And check TNC Status) + + return ((TNC->CONNECTED) << 8 | TNC->Streams[0].Disconnecting << 15); // OK + + case 4: // reinit7 + + return 0; + + case 5: // Close + + return 0; + + case 6: // Scan Stop Interface + + Param = (size_t)buff; + + if (Param == 2) // Check Permission (Shouldn't happen) + { + Debugprintf("Scan Check Permission called on SIXPACK"); + return 1; // OK to change + } + + if (Param == 1) // Request Permission + { + if (!TNC->CONNECTED) + return 0; // No connection so no interlock + + if (TNC->ConnectPending == 0 && TNC->PTTState == 0) + { + SerialSendCommand(TNC, "CONOK OFF"); + TNC->GavePermission = TRUE; + return 0; // OK to Change + } + + if (TNC->ConnectPending) + TNC->ConnectPending--; // Time out if set too long + + return TRUE; + } + + if (Param == 3) // Release Permission + { + if (TNC->GavePermission) + { + TNC->GavePermission = FALSE; + if (TNC->ARDOPCurrentMode[0] != 'S') // Skip + SerialSendCommand(TNC, "CONOK ON"); + } + return 0; + } + + // Param is Address of a struct ScanEntry + + Scan = (struct ScanEntry *)buff; + return 0; + } + return 0; +} + +VOID SIXPACKReleaseTNC(struct TNCINFO * TNC) +{ + // Set mycall back to Node or Port Call, and Start Scanner + + UCHAR TXMsg[64]; + + // Start Scanner + + sprintf(TXMsg, "%d SCANSTART 15", TNC->Port); + Rig_Command( (TRANSPORTENTRY *) -1, TXMsg); + + strcpy(TNC->WEB_TNCSTATE, "Free"); + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + + ReleaseOtherPorts(TNC); +} + +VOID SIXPACKSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC) +{ +} + +VOID SIXPACKReleasePort(struct TNCINFO * TNC) +{ +} + +static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) +{ + int Len = sprintf(Buff, "" + "" + "VARA Status" + "

SIXPACK Status" + "

", + TNC->Port); + + + Len += sprintf(&Buff[Len], ""); + + Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); + Len += sprintf(&Buff[Len], "", TNC->WEB_CHANSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_PROTOSTATE); + Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); +// Len += sprintf(&Buff[Len], "", TNC->WEB_RESTARTS); + Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Channel State%s
Proto State%s
Traffic%s
TNC Restarts
"); + + Len += sprintf(&Buff[Len], "", TNC->WebBuffer); + Len = DoScanLine(TNC, Buff, Len); + + return Len; +} + + + +VOID * SIXPACKExtInit(EXTPORTDATA * PortEntry) +{ + int port; + char Msg[255]; + char * ptr; + struct TNCINFO * TNC; + char * TempScript; + struct PORTCONTROL * PORT = &PortEntry->PORTCONTROL; + + port = PORT->PORTNUMBER; + + if (TNCInfo[port]) // If restarting, free old config + free(TNCInfo[port]); + + TNC = TNCInfo[port] = malloc(sizeof(struct TNCINFO)); + memset(TNC, 0, sizeof(struct TNCINFO)); + + TNC->InitScript = malloc(1000); + TNC->InitScript[0] = 0; + + if (PortConfig[port]) // May not have config + ReadConfigFile(port, ProcessLine); + + TNC = TNCInfo[port]; + + if (TNC == NULL) + { + // Not defined in Config file + + sprintf(Msg," ** Error - no info in BPQ32.cfg for this port\n"); + WritetoConsole(Msg); + + return ExtProc; + } + + TNC->sixPack = zalloc(sizeof(struct sixPackTNCInfo)); + + TNC->Port = port; + TNC->Hardware = H_SIXPACK; + TNC->ARDOPBuffer = malloc(8192); + + TNC->PortRecord = PortEntry; + + if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) + memcpy(TNC->NodeCall, MYNODECALL, 10); + else + ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); + + if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) + TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; + + PortEntry->PORTCONTROL.PROTOCOL = 10; + PortEntry->PORTCONTROL.PORTQUALITY = 0; + PortEntry->PORTCONTROL.USERS = 1; // Max 1 Session + + TNC->PacketChannels = 0; + + PortEntry->MAXHOSTMODESESSIONS = 1; + + PortEntry->SCANCAPABILITIES = SIMPLE; // Scan Control - pending connect only + PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream + + PortEntry->PORTCONTROL.UICAPABLE = TRUE; + + if (PortEntry->PORTCONTROL.PORTPACLEN == 0) + PortEntry->PORTCONTROL.PORTPACLEN = 236; + + TNC->SuspendPortProc = SIXPACKSuspendPort; + TNC->ReleasePortProc = SIXPACKReleasePort; + +// PortEntry->PORTCONTROL.PORTSTARTCODE = KISSStartPort; +// PortEntry->PORTCONTROL.PORTSTOPCODE = KISSStopPort; + + ptr=strchr(TNC->NodeCall, ' '); + if (ptr) *(ptr) = 0; // Null Terminate + + // Set Essential Params and MYCALL + + // Put overridable ones on front, essential ones on end + + TempScript = zalloc(1000); + + // cant think of any yet + + if (TNC->InitScript) + { + strcat(TempScript, TNC->InitScript); + free(TNC->InitScript); + } + + TNC->InitScript = TempScript; + + if (TNC->WL2K == NULL) + if (PortEntry->PORTCONTROL.WL2KInfo.RMSCall[0]) // Alrerady decoded + TNC->WL2K = &PortEntry->PORTCONTROL.WL2KInfo; + + PortEntry->PORTCONTROL.TNC = TNC; + + TNC->WebWindowProc = WebProc; + TNC->WebWinX = 520; + TNC->WebWinY = 500; + TNC->WebBuffer = zalloc(5000); + + TNC->WEB_COMMSSTATE = zalloc(100); + TNC->WEB_TNCSTATE = zalloc(100); + TNC->WEB_CHANSTATE = zalloc(100); + TNC->WEB_BUFFERS = zalloc(100); + TNC->WEB_PROTOSTATE = zalloc(100); + TNC->WEB_RESTARTTIME = zalloc(100); + TNC->WEB_RESTARTS = zalloc(100); + + TNC->WEB_MODE = zalloc(20); + TNC->WEB_TRAFFIC = zalloc(100); + + +#ifndef LINBPQ + + CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 700, 450, ForcedClose); + + CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "Channel State", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_CHANSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "Proto State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_PROTOSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "0 0 0 0", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); + + CreateWindowEx(0, "STATIC", "TNC Restarts", WS_CHILD | WS_VISIBLE,10,138,100,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_RESTARTS = CreateWindowEx(0, "STATIC", "0", WS_CHILD | WS_VISIBLE,116,138,40,20 , TNC->hDlg, NULL, hInstance, NULL); + CreateWindowEx(0, "STATIC", "Last Restart", WS_CHILD | WS_VISIBLE,140,138,100,20, TNC->hDlg, NULL, hInstance, NULL); + TNC->xIDC_RESTARTTIME = CreateWindowEx(0, "STATIC", "Never", WS_CHILD | WS_VISIBLE,250,138,200,20, TNC->hDlg, NULL, hInstance, NULL); + + TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT | + LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL, + 0,170,250,300, TNC->hDlg, NULL, hInstance, NULL); + + TNC->ClientHeight = 450; + TNC->ClientWidth = 500; + + TNC->hMenu = CreatePopupMenu(); + + AppendMenu(TNC->hMenu, MF_STRING, WINMOR_KILL, "Kill TNC"); + AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTART, "Kill and Restart TNC"); + AppendMenu(TNC->hMenu, MF_STRING, WINMOR_RESTARTAFTERFAILURE, "Restart TNC after failed Connection"); + CheckMenuItem(TNC->hMenu, WINMOR_RESTARTAFTERFAILURE, (TNC->RestartAfterFailure) ? MF_CHECKED : MF_UNCHECKED); + AppendMenu(TNC->hMenu, MF_STRING, ARDOP_ABORT, "Abort Current Session"); + + MoveWindows(TNC); +#endif + Consoleprintf("SIXPACK Host %s %d", TNC->HostName, htons(TNC->destaddr.sin_port)); + + Connectto6Pack(port); + + time(&TNC->lasttime); // Get initial time value + + return ExtProc; +} + + +VOID TidyClose(struct TNCINFO * TNC, int Stream) +{ + // If all acked, send disc + + if (TNC->Streams[Stream].BytesOutstanding == 0) + SerialSendCommand(TNC, "DISCONNECT\r"); +} + +VOID ForcedClose(struct TNCINFO * TNC, int Stream) +{ + SerialSendCommand(TNC, "DISCONNECT\r"); +} + +VOID CloseComplete(struct TNCINFO * TNC, int Stream) +{ + if (Stream == 0) + { + SIXPACKReleaseTNC(TNC); + } +} + + +static int KissDecode(UCHAR * inbuff, UCHAR * outbuff, int len) +{ + int i,txptr=0; + UCHAR c; + + for (i=0;iInputLen > 8000) // Shouldnt have packets longer than this + TNC->InputLen=0; + + InputLen = recv(TNC->TCPSock, &TNC->ARDOPBuffer[TNC->InputLen], 8192 - TNC->InputLen, 0); + + if (InputLen == 0 || InputLen == SOCKET_ERROR) + { + // Does this mean closed? + + int err = GetLastError(); + + closesocket(TNC->TCPSock); + + TNC->TCPSock = 0; + + TNC->CONNECTED = FALSE; + TNC->Streams[0].ReportDISC = TRUE; + + sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); + MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + + return; + } + + TNC->InputLen += InputLen; + + // Extract and decode KISS frames + + ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND + + while (ptr) // FEND in buffer + { + ptr++; + + MsgLen = ptr - TNC->ARDOPBuffer; + + if (MsgLen > 360) + { + TNC->InputLen = 0; + return; + } + + TNC->InputLen -= MsgLen; + + if (MsgLen > 1) + { + PMESSAGE Buff = GetBuff(); + + MsgLen = KissDecode(TNC->ARDOPBuffer, Buffer, MsgLen); + + // we dont need the FENDS or control byte + + MsgLen -= 3; + + if (Buff) + { + memcpy(&Buff->DEST, &Buffer[2], MsgLen); + MsgLen += (3 + sizeof(void *)); + + PutLengthinBuffer((PDATAMESSAGE)Buff, MsgLen); // Needed for arm5 portability + + C_Q_ADD(&TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buff); + } + } + + if (TNC->InputLen == 0) + return; + + memmove(TNC->ARDOPBuffer, ptr, TNC->InputLen); + ptr = memchr(TNC->ARDOPBuffer + 1, FEND, TNC->InputLen - 1); // Ignore leading FEND + } + +} + + + +/* + +// we dont need the control byte + +len --; + +if (Buffer) +{ +memcpy(&Buffer->DEST, &Port->RXMSG[1], len); +len += (3 + sizeof(void *)); + +PutLengthinBuffer((PDATAMESSAGE)Buffer, len); // Needed for arm5 portability + +C_Q_ADD(TNC->PortRecord->PORTCONTROL.PORTRX_Q, (UINT *)Buffer); +} + +*/ + +// TNC->InputLen -= MsgLen; +// goto loop; + + + + +void AttachSIXPACK(struct PORTCONTROL * PORT, MESSAGE * Buffer) +{ + // SABM on HFKISS port. L2 code will accepr call and connect to appl if necessary, but + // need to attach the port + + char Call[16] = ""; + char OrigCall[16] = ""; + struct TNCINFO * TNC = PORT->TNC; + struct WL2KInfo * WL2K = TNC->WL2K; + + if (TNC->PortRecord->ATTACHEDSESSIONS[0] == 0) + { + TRANSPORTENTRY * SESS; + struct TNCINFO * TNC = PORT->TNC; + + // Incoming Connect + + Call[ConvFromAX25(Buffer->DEST, Call)] = 0; + OrigCall[ConvFromAX25(Buffer->ORIGIN, OrigCall)] = 0; + + // Stop other ports in same group + + SuspendOtherPorts(TNC); + + TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit + + ProcessIncommingConnectEx(TNC, Call, 0, FALSE, FALSE); + + SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; + + SESS->Mode = TNC->WL2KMode; + + TNC->ConnectPending = FALSE; + + if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT")) + { + sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", OrigCall, Call, TNC->RIG->Valchar); + SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq + if (SESS->Frequency == 1500) + { + // try to get from WL2K record + + if (WL2K) + { + SESS->Frequency = WL2K->Freq; + } + } + SESS->Mode = TNC->WL2KMode; + } + else + { + sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", OrigCall, Call); + if (WL2K) + { + SESS->Frequency = WL2K->Freq; + SESS->Mode = WL2K->mode; + } + } + + if (WL2K) + strcpy(SESS->RMSCall, WL2K->RMSCall); + + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + } +} + +void DetachSIXPACK(struct PORTCONTROL * PORT) +{ + // L2 Link Closed. Detach. + + struct TNCINFO * TNC = PORT->TNC; + struct STREAMINFO * STREAM = &TNC->Streams[0]; + + if (STREAM->Attached) + STREAM->ReportDISC = TRUE; // Tell Node + + STREAM->Connecting = FALSE; + STREAM->Connected = FALSE; + +} + +void SIXPACKConnected(struct PORTCONTROL * PORT, struct _LINKTABLE * LINK) +{ + // UA received when connecting + + struct TNCINFO * TNC = PORT->TNC; + struct STREAMINFO * STREAM = &TNC->Streams[0]; + struct WL2KInfo * WL2K = TNC->WL2K; + + TRANSPORTENTRY * SESS; + char Call[16] = ""; + char OrigCall[16] = ""; + + + if (STREAM->Connecting) + { + STREAM->Connecting = FALSE; + STREAM->Connected = TRUE; + + Call[ConvFromAX25(LINK->LINKCALL, Call)] = 0; + OrigCall[ConvFromAX25(LINK->OURCALL, OrigCall)] = 0; + + TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit + + SESS = TNC->PortRecord->ATTACHEDSESSIONS[0]; + SESS->Mode = TNC->WL2KMode; + + if (TNC->RIG && TNC->RIG != &TNC->DummyRig && strcmp(TNC->RIG->RigName, "PTT")) + { + sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", OrigCall, Call, TNC->RIG->Valchar); + SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq + + if (SESS->Frequency == 1500) + { + // try to get from WL2K record + + if (WL2K) + { + SESS->Frequency = WL2K->Freq; + } + } + SESS->Mode = TNC->WL2KMode; + } + else + { + sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", OrigCall, Call); + + if (WL2K) + { + SESS->Frequency = WL2K->Freq; + SESS->Mode = WL2K->mode; + } + } + + if (WL2K) + strcpy(SESS->RMSCall, WL2K->RMSCall); + + MySetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); + } +} + + + +VOID x6PackThead(void * portptr); + +int Connectto6Pack(int port) +{ + _beginthread(x6PackThead, 0, (void *)(size_t)port); + + return 0; +} + +VOID x6PackThead(void * portptr) +{ + // 6pack over TNC thread + + // Opens socket and looks for data + + int port = (int)(size_t)portptr; + char Msg[255]; + int err, i, ret; + u_long param=1; + BOOL bcopt=TRUE; + struct hostent * HostEnt; + struct TNCINFO * TNC = TNCInfo[port]; + fd_set readfs; + fd_set errorfs; + struct timeval timeout; + char * ptr1; + char * ptr2; + UINT * buffptr; + int reinitTimer = 0; + int linkactive = 0; + + struct sixPackPortInfo * sixPack = TNC->sixPack; + + if (sixPack == NULL || TNC->HostName == NULL) + return; + + TNC->BusyFlags = 0; + + TNC->CONNECTING = TRUE; + + Sleep(3000); // Allow init to complete + +#ifdef WIN32 + if (strcmp(TNC->HostName, "127.0.0.1") == 0) + { + // can only check if running on local host + + TNC->PID = GetListeningPortsPID(TNC->destaddr.sin_port); + if (TNC->PID == 0) + { + TNC->CONNECTING = FALSE; + return; // Not listening so no point trying to connect + } + + // Get the File Name in case we want to restart it. + + if (TNC->ProgramPath == NULL) + { + if (GetModuleFileNameExPtr) + { + HANDLE hProc; + char ExeName[256] = ""; + + hProc = OpenProcess(PROCESS_QUERY_INFORMATION |PROCESS_VM_READ, FALSE, TNC->PID); + + if (hProc) + { + GetModuleFileNameExPtr(hProc, 0, ExeName, 255); + CloseHandle(hProc); + + TNC->ProgramPath = _strdup(ExeName); + } + } + } + } +#endif + +// // If we started the TNC make sure it is still running. + +// if (!IsProcess(TNC->PID)) +// { +// RestartTNC(TNC); +// Sleep(3000); +// } + + + TNC->destaddr.sin_addr.s_addr = inet_addr(TNC->HostName); + + if (TNC->destaddr.sin_addr.s_addr == INADDR_NONE) + { + // Resolve name to address + + HostEnt = gethostbyname (TNC->HostName); + + if (!HostEnt) + { + TNC->CONNECTING = FALSE; + return; // Resolve failed + } + memcpy(&TNC->destaddr.sin_addr.s_addr,HostEnt->h_addr,4); + memcpy(&TNC->Datadestaddr.sin_addr.s_addr,HostEnt->h_addr,4); + } + +// closesocket(TNC->TCPSock); + + TNC->TCPSock=socket(AF_INET,SOCK_STREAM,0); + + if (TNC->TCPSock == INVALID_SOCKET) + { + i=sprintf(Msg, "Socket Failed for 6Pack socket - error code = %d\r\n", WSAGetLastError()); + WritetoConsole(Msg); + + TNC->CONNECTING = FALSE; + return; + } + + setsockopt(TNC->TCPSock, SOL_SOCKET, SO_REUSEADDR, (const char FAR *)&bcopt, 4); + + sinx.sin_family = AF_INET; + sinx.sin_addr.s_addr = INADDR_ANY; + sinx.sin_port = 0; + + if (connect(TNC->TCPSock,(LPSOCKADDR) &TNC->destaddr,sizeof(TNC->destaddr)) == 0) + { + // + // Connected successful + // + } + else + { + if (TNC->Alerted == FALSE) + { + err=WSAGetLastError(); + i=sprintf(Msg, "Connect Failed for 6Pack socket - error code = %d\r\n", err); + WritetoConsole(Msg); + sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC failed"); + MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + + TNC->Alerted = TRUE; + } + + closesocket(TNC->TCPSock); + TNC->TCPSock = 0; + TNC->CONNECTING = FALSE; + return; + } + + Sleep(1000); + + TNC->LastFreq = 0; // so V4 display will be updated + + TNC->CONNECTING = FALSE; + TNC->CONNECTED = TRUE; + TNC->BusyFlags = 0; + TNC->InputLen = 0; + + TNC->Alerted = TRUE; + + sprintf(TNC->WEB_COMMSSTATE, "Connected to TNC"); + MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + + FreeSemaphore(&Semaphore); + + sprintf(Msg, "Connected to TNC Port %d\r\n", TNC->Port); + WritetoConsole(Msg); + + while (TNC->CONNECTED) + { + FD_ZERO(&readfs); + FD_ZERO(&errorfs); + + FD_SET(TNC->TCPSock,&readfs); + FD_SET(TNC->TCPSock,&errorfs); + + timeout.tv_sec = 1; + timeout.tv_usec = 0; // We use this to run timeouts + + ret = select((int)TNC->TCPSock + 1, &readfs, NULL, &errorfs, &timeout); + + if (ret == SOCKET_ERROR) + { + Debugprintf("6Pack Select failed %d ", WSAGetLastError()); + goto Lost; + } + if (ret > 0) + { + // See what happened + + if (FD_ISSET(TNC->TCPSock, &readfs)) + { + GetSemaphore(&Semaphore, 52); + SixPackProcessReceivedPacket(TNC); + FreeSemaphore(&Semaphore); + } + + if (FD_ISSET(TNC->TCPSock, &errorfs)) + { +Lost: + sprintf(Msg, "6Pack Connection lost for Port %d\r\n", TNC->Port); + WritetoConsole(Msg); + + sprintf(TNC->WEB_COMMSSTATE, "Connection to TNC lost"); + MySetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); + + TNC->CONNECTED = FALSE; + TNC->Alerted = FALSE; + + if (TNC->PTTMode) + Rig_PTT(TNC, FALSE); // Make sure PTT is down + + if (TNC->Streams[0].Attached) + TNC->Streams[0].ReportDISC = TRUE; + + TNC->TCPSock = 0; + return; + } + } + else + { + // Timeout. See if we need to reinit tnc chain + + if (sixPack->linkOK == 0) + { + sixPack->reinitTimer++; + if (sixPack->reinitTimer > 30) + { + // send SIXP_INIT_CMD which should rescan the tnc chain + + unsigned char Msg = SIXP_INIT_CMD; + int txlen = send(TNC->TCPSock, &Msg, 1, 0); + sixPack->reinitTimer = 0; + } + } + } + + } + sprintf(Msg, "6Pack Thread Terminated Port %d\r\n", TNC->Port); + WritetoConsole(Msg); +} + + + + + + diff --git a/ARDOP.c b/ARDOP.c index 01ee591..61fab6b 100644 --- a/ARDOP.c +++ b/ARDOP.c @@ -880,6 +880,17 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) } } + // Check ATTACH time limit + + if (STREAM->Attached) + { + if (STREAM->AttachTime && TNC->AttachTimeLimit && time(NULL) > (TNC->AttachTimeLimit + STREAM->AttachTime)) + { + STREAM->ReportDISC = 1; + STREAM->AttachTime = 0; + } + } + if (TNC->ARDOPCommsMode != 'T') // S I or E { ARDOPSCSCheckRX(TNC); @@ -1190,6 +1201,7 @@ static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) Debugprintf("ARDOP New Attach Stream %d DEDStream %d", Stream, STREAM->DEDStream); STREAM->Attached = TRUE; + STREAM->AttachTime = time(NULL); calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, TNC->Streams[Stream].MyCall); TNC->Streams[Stream].MyCall[calllen] = 0; diff --git a/BBSUtilities.c b/BBSUtilities.c index d62b3c5..a3b9bd8 100644 --- a/BBSUtilities.c +++ b/BBSUtilities.c @@ -11762,300 +11762,258 @@ BOOL CheckforMIME(SocketConn * sockptr, char * Msg, char ** Body, int * MsgLen); #include #include -typedef struct _POPENRET -{ - FILE * fp; - pid_t pid; -} POPENRET; +// G8BPQ Version of Steve G7TAJ's code -/* -* Check if the PG is still running after 5 sec -* if so, kill it +int pgret = 9999; +int pindex = 0; + +void sigchild_handler(int sig , siginfo_t * siginfo, void * ucontext) +{ +/* • SIGCHLD fills in si_pid, si_uid, si_status, si_utime, and + si_stime, providing information about the child. The si_pid + field is the process ID of the child; si_uid is the child's + real user ID. The si_status field contains the exit status of + the child (if si_code is CLD_EXITED), or the signal number + that caused the process to change state. */ -void run_pgTimeoutThread( pid_t process ) -{ -// printf("watchdog thread: PID of subprocess: %d\n", process); -// fflush(stdout); - Sleep(5000); - // if still running PID (?) then kill. - if ( getpgid(process) >= 0 ) - { - Debugprintf("watchdog thread: Still running, so killing %d ... ", process); - if ( kill( -process, SIGKILL ) == 0 ) - Debugprintf("Killed PG watchdog Process %d", process); - else - Debugprintf("Failed to kill PG watchdog Process %d", process); - } - -// Debugprintf("watchdog thread: PID=%d Exit", process); -// fflush(stdout); +// printf("SIGCHLD PID %d Code %d status %d\n", siginfo->si_pid, siginfo->si_code, siginfo->si_status); + pgret = siginfo->si_status; } -//https://sources.debian.org/src/cron/3.0pl1-45/popen.c/ - -POPENRET my_popen(char *program, char *type, CIRCUIT *conn) +void run_pg(CIRCUIT * conn, struct UserInfo * user) { register char *cp; FILE *iop; int argc, pdes[2]; pid_t pid; - POPENRET PRET; - if (*type != 'r' && *type != 'w' || type[1]) - return(PRET); - if (pipe(pdes) < 0) - return(PRET); + pgret = 9999; + + int index = user->Temp->PG_INDEX; iop = NULL; - switch(pid = fork()) { + + conn->InputBuffer[conn->InputLen] = 0; + strlop(conn->InputBuffer, 13); + conn->InputLen = 0; + + if (!user->Temp->RUNPGPARAMS) + user->Temp->RUNPGPARAMS = (RUNPGARGS_PTR) zalloc(sizeof(RUNPGARGS)); + + user->Temp->RUNPGPARAMS->user = user; + user->Temp->RUNPGPARAMS->conn = conn; + strncpy(user->Temp->RUNPGPARAMS->InputBuffer, conn->InputBuffer, 80); // needs to be length of actual input! + user->Temp->RUNPGPARAMS->Len = conn->InputLen; + + if (conn == 0 || user == 0) + { + Debugprintf("run_pg conn or user null"); + return; + } + + // Build command line. Parmas are: + + // - Callsign (format as F6FBB-8). + // - Level number (0 is the first time, up to 99). + // - Flags of the user (binary number as user`s mask of INIT.SRV). + // - Record number of the user in INF.SYS. + // - Received data (each word is a new argument). + + // BPQ doesn't support params 3 and 4 (but may supply copy of user record later) + + char cmd[20]; + char *ptr = cmd; + char pg_dir[MAX_PATH]; + char log_file[50] = "pg.log"; + char call[10]; + char data[80]; + char line[80]; + size_t bufsize = 80; + + strcpy(pg_dir, BaseDir); + strcat(pg_dir, "/PG/"); + sprintf(cmd, "./%s", SERVERLIST[user->Temp->PG_SERVER][1] ); + + sprintf(line, "%s%s", pg_dir, SERVERLIST[user->Temp->PG_SERVER][1]); +// printf("PG Prog %s%s\n", pg_dir, SERVERLIST[user->Temp->PG_SERVER][1]); + + // check file exists and is executable + + if (access(line, F_OK) == -1 || access(line, X_OK) == -1) + { + Debugprintf("%s FileNotFound || not executable", line); + BBSputs(conn, "Error running PG Server\r"); + conn->InputMode=0; + SendPrompt(conn, user); + return; + } + + strcpy(call, conn->UserPointer->Call); + index = user->Temp->PG_INDEX; + + // remove ';' from input for security reasons + + ptr = strchr(user->Temp->RUNPGPARAMS->InputBuffer, ';'); + if (ptr) + *ptr = '\0'; + + sprintf(data, "%s %d 0 0 %s", call, index, user->Temp->RUNPGPARAMS->InputBuffer); +// printf("PG Params %s\n", data); + + conn->InputBufferLen = 0; + + char buf[256]; + + sprintf (buf, "%s %s", line, data); // buf is command to exec +// printf ("PG exec cmd %s\n", buf); + + // Create pipe for reading PG program STDOUT + + if (pipe(pdes) < 0) + { + Debugprintf("run_pg pipe failed"); + BBSputs(conn, "Error running PG Server (pipe() failed)\r"); + conn->InputMode=0; + SendPrompt(conn, user); + return; + } + + // We will just fork and execute program. For now don't create a new thread + + // Trap sigchild so we can tell when it exits and get return code + + struct sigaction act; + memset(&act, 0, sizeof(struct sigaction)); + act.sa_flags = SA_RESETHAND | SA_SIGINFO; // Restore default handler when called + act.sa_sigaction = sigchild_handler; + sigaction(SIGCHLD, &act, NULL); + + switch(pid = fork()) + { case -1: /* error */ (void)close(pdes[0]); (void)close(pdes[1]); - return PRET; + Debugprintf("run_pg fork failed"); + BBSputs(conn, "Error running PG Server (fork() failed)\r"); + conn->InputMode=0; + SendPrompt(conn, user); + + return; + case 0: /* child */ - if (*type == 'r') { - if (pdes[1] != 1) { - dup2(pdes[1], 1); - dup2(pdes[1], 2); - (void)close(pdes[1]); - } - (void)close(pdes[0]); - } else { - if (pdes[0] != 0) { - dup2(pdes[0], 0); - (void)close(pdes[0]); - } + + if (pdes[1] != 1) + { + dup2(pdes[1], 1); + dup2(pdes[1], 2); (void)close(pdes[1]); } - setpgid(-pid,pid); - char *args[] = {"sh", "-c", program, NULL}; - execve("/bin/sh", args, NULL); + (void)close(pdes[0]); + + setpgid(0, pid); + + char *args[] = {"sh", "-c", buf, NULL}; + execve("/bin/sh", args, NULL); + _exit(1); } /* parent */ - _beginthread((void (*)(void *))run_pgTimeoutThread, 0, (VOID *) pid ); +// printf("child PID %d\n", pid); - if (*type == 'r') { - iop = fdopen(pdes[0], type); - (void)close(pdes[1]); - } else { - iop = fdopen(pdes[1], type); - (void)close(pdes[0]); + struct timespec duration; + duration.tv_sec = 5; + duration.tv_nsec = 0; + + nanosleep(&duration, &duration); // Will be interrupted by SIGCHLD + +// printf("PG retcode %d\n", pgret); + + if (pgret == 9999) // Process still running + { + BBSputs(conn, "PG Program Looping\r"); + kill(pid, SIGKILL); + user->Temp->PG_INDEX = 0; + conn->InputMode=0; + SendPrompt(conn, user); + return; } + if (pgret > 127) + { + // Probably killed by signal + + int err = pgret - 128; + char errmsg[256]; + + sprintf(errmsg, "PG Signal %s received\n", strsignal(err)); + + BBSputs(conn, errmsg); + user->Temp->PG_INDEX = 0; + conn->InputMode=0; + SendPrompt(conn, user); + return; + } + + // Send STDOUT from PG program to BBS user + + iop = fdopen(pdes[0], "r"); + (void)close(pdes[1]); + char buffer[128]; while (fgets(buffer, sizeof(buffer), iop) != NULL) { BBSputs(conn, buffer); buffer[0] = '\0'; } - PRET.fp = iop; - PRET.pid= pid; - return(PRET); -} - -int -my_pclose( POPENRET pret ) -{ - register int fdes; - sigset_t omask, mask; - int stat_loc; - pid_t pid; - FILE * iop = pret.fp; - - fdes = fileno(iop); - (void)fclose(iop); - - sigemptyset(&mask); - sigaddset(&mask, SIGQUIT); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGHUP); - sigprocmask(SIG_BLOCK, &mask, &omask); - pid = waitpid(pret.pid, &stat_loc, 0); - sigprocmask(SIG_SETMASK, &omask, NULL); - if (pid == -1 || !WIFEXITED(stat_loc)) - return -1; - return stat_loc; -} - - -int run_server (char **cmd, int nb_cmd, int mode, char *log, char *pgdir, char *data, CIRCUIT * conn) -{ - int i; - int ret = 0; - FILE *fp; - POPENRET PRET; - pid_t pid; - char *ptr; - char file[256]; - char buf[256]; - char dir[256]; - char arg[256]; - - if (mode) - // sprintf (file, " >>%s", log); - // sprintf (file, " | tee -a %s", log); - sprintf(file, "" ); - else - sprintf (file, " InputMode=0; + SendPrompt(conn, user); + break; + case 1: + index++; // inc & keep in PG + break; - sprintf (dir, "cd %s ; ", pgdir); - } - else - *dir = '\0'; + case 2: + + index=0; // disconnect + conn->InputMode=0; + Disconnect(conn->BPQStream); + break; - *arg = '\0'; + case 3: + Debugprintf("data->BBS & end"); + break; - if (data) - { - /* remove ';' security reasons */ - ptr = strchr(data, ';'); - if (ptr) - *ptr = '\0'; + case 4: + Debugprintf("data->BBS and inc %d", pindex++); + break; + case 5: + Debugprintf("call no inc %d", pgret); + break; - sprintf (arg, " %s ", data); - } - - - for (i = 0; i < nb_cmd; i++) - { - /* remove ';' security reasons */ - ptr = strchr(cmd[i], ';'); - if (ptr) - *ptr = '\0'; - - sprintf (buf, "%s%s%s%s", dir, cmd[i], arg, file); - - PRET = my_popen (buf, "r", conn); - - if (PRET.fp == NULL) - Debugprintf ("Failed to run PG command %s\n", cmd[i] ); - - ret = my_pclose( PRET ); - ret = ret >> 8; - - if (verbose) { - Debugprintf ("Debug: command = {%s}\n", buf); - Debugprintf ("Debug: exit code = %d\n", ret); - } - - /* fail-safe bypass if executable isn't found (exit code 127) (was ret ==127)*/ - if (ret > 5) // should never be more than 5 - ret = 0; - } - return ( ret ); -} - - -void run_pg( CIRCUIT * conn, struct UserInfo * user ) -{ - - if (!user->Temp->RUNPGPARAMS) { - user->Temp->RUNPGPARAMS = (RUNPGARGS_PTR) zalloc(sizeof(RUNPGARGS)); - } - - user->Temp->RUNPGPARAMS->user = user; - user->Temp->RUNPGPARAMS->conn = conn; - strncpy(user->Temp->RUNPGPARAMS->InputBuffer, conn->InputBuffer, 80); // needs to be length of actual input! - user->Temp->RUNPGPARAMS->Len = conn->InputLen; - - if ( conn == 0 || user == 0 ) { - Debugprintf("run_pg null err"); - return; - } - - _beginthread((void (*)(void *))startrun_pgThread, 0, user->Temp->RUNPGPARAMS ); - - return; -} - - -void startrun_pgThread( RUNPGARGS_PTR Args ) { - - CIRCUIT * conn = Args->conn; - struct UserInfo * user = Args->user; - - char cmd[20]; - sprintf( cmd, "./%s", SERVERLIST[user->Temp->PG_SERVER][1] ); - char *ptr = cmd; - char pg_dir[MAX_PATH]; - char log_file[50] = "pg.log"; - char call[6]; - char data[80]; - char line[80]; - char *line_ptr = line; - int index; - char *data_ptr = data; - size_t bufsize = 80; - - strcpy(pg_dir, BaseDir); - strcat(pg_dir, "/PG/"); - - sprintf(line, "%s%s", pg_dir, SERVERLIST[user->Temp->PG_SERVER][1]); - - // check file exists and is executable - if (access(line, F_OK) == -1 || access(line, X_OK) == -1) { - Debugprintf("%s FileNotFound || Not EXE", line); - BBSputs(conn, "Error running PG Server\r"); + default: + BBSputs(conn, "PG unexexpected response\r"); + user->Temp->PG_INDEX = 0; conn->InputMode=0; SendPrompt(conn, user); return; } - strcpy( call, conn->UserPointer->Call); - // sprintf( log_file, "%s-%d.log", call, conn); - index = user->Temp->PG_INDEX; + user->Temp->PG_INDEX = index; - line[0] = '\0'; - int Len = Args->Len; - UCHAR * Msg = Args->InputBuffer; - strncpy( line, Msg, Len); - line[ Len - 1 ] = 0; //remove LF - - sprintf( data, "%s %d 0 0 %s", call, index, line); - - // clear the input queue - conn->InputLen = 0; - conn->InputBufferLen = 0; - - int ret = run_server (&ptr, 1, 1, log_file, pg_dir, data_ptr, conn); - - switch (ret) - { - case -1: // ERROR or forced closed - case 0: index=0; // Goodbye/Exit - conn->InputMode=0; - SendPrompt(conn, user); - break; - case 1: index++; // inc & keep in PG - break; - case 2: index=0; // disconnect - conn->InputMode=0; - Disconnect(conn->BPQStream); - break; - case 3: Debugprintf("data->BBS & end"); - break; - case 4: Debugprintf("data->BBS and inc %d", index++); - break; - case 5: Debugprintf("call no inc %d", ret); - break; - - } - - user->Temp->PG_INDEX=index; +// printf("runpg return index = %d\n", index); } + + /*---- G7TAJ END ----- */ #else @@ -12076,7 +12034,7 @@ void ReadFromPipe(void); void run_pg( CIRCUIT * conn, struct UserInfo * user ) { - // Run PG program, rend anything from program's stdout to the user + // Run PG program, read anything from program's stdout to the user int retcode = -1; SECURITY_ATTRIBUTES saAttr; @@ -12251,7 +12209,7 @@ void run_pg( CIRCUIT * conn, struct UserInfo * user ) case 4: - // Send Output to BBS - was down above + // Send Output to BBS - was done above break; case 5: diff --git a/BPQChat.vcproj.NOTTSDESKTOP.John.user b/BPQChat.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/BPQChat.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQMail.c b/BPQMail.c index e528f98..402d87f 100644 --- a/BPQMail.c +++ b/BPQMail.c @@ -1137,6 +1137,7 @@ // Improve "New User" frequency determination (39) // Allow selection of 2 or 4 character country codes for forward processing (39) // Fix Send P to multiple BBS's when routing on HR (40) +// Rewrite PG server code on Lunux (41) #include "bpqmail.h" #include "winstdint.h" diff --git a/BPQMail.vcproj.NOTTSDESKTOP.John.user b/BPQMail.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/BPQMail.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQMail.vcproj.SKIGACER.johnw.user b/BPQMail.vcproj.SKIGACER.johnw.user new file mode 100644 index 0000000..b5b0536 --- /dev/null +++ b/BPQMail.vcproj.SKIGACER.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..0cd9a72 --- /dev/null +++ b/BPQWinAPP.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/BPQWinAPP.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/Bpq32.c b/Bpq32.c index 7059a56..d98b6ea 100644 --- a/Bpq32.c +++ b/Bpq32.c @@ -1219,6 +1219,9 @@ along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses // Fix ICF8101 Mode setting (37) // Kill link if we are getting repeated RR(F) after timeout // (Indicating other station is seeing our RR(P) but not the resent I frame) (40) +// Change default of SECURETELNET to 1 (41) +// Add optional ATTACH time limit for ARDOP (42) +// Fix buffer overflow risk in HTTP Terminal(42) @@ -1313,6 +1316,7 @@ void * KISSHFExtInit(EXTPORTDATA * PortEntry); void * WinRPRExtInit(EXTPORTDATA * PortEntry); void * HSMODEMExtInit(EXTPORTDATA * PortEntry); void * FreeDataExtInit(EXTPORTDATA * PortEntry); +void * SIXPACKExtInit(EXTPORTDATA * PortEntry); extern char * ConfigBuffer; // Config Area VOID REMOVENODE(dest_list * DEST); @@ -3950,6 +3954,9 @@ VOID * InitializeExtDriver(PEXTPORTDATA PORTVEC) if (strstr(Value, "FREEDATA")) return FreeDataExtInit; + if (strstr(Value, "6PACK")) + return SIXPACKExtInit; + ExtDriver = LoadLibrary(Value); if (ExtDriver == NULL) diff --git a/CBPQ32.vcproj b/CBPQ32.vcproj index 0648ae6..a580f7a 100644 --- a/CBPQ32.vcproj +++ b/CBPQ32.vcproj @@ -57,7 +57,7 @@ UsePrecompiledHeader="0" AssemblerOutput="2" AssemblerListingLocation="c:\devprogs\bpq32\listings\debug\" - BrowseInformation="0" + BrowseInformation="1" WarningLevel="3" Detect64BitPortabilityProblems="false" DebugInformationFormat="4" @@ -234,6 +234,10 @@ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + + diff --git a/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..ddedde2 --- /dev/null +++ b/CBPQ32.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CBPQ32.vcproj.NOTTSDESKTOP.John.user b/CBPQ32.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..270b67b --- /dev/null +++ b/CBPQ32.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CBPQ32.vcproj.SKIGACER.johnw.user b/CBPQ32.vcproj.SKIGACER.johnw.user new file mode 100644 index 0000000..f8a6101 --- /dev/null +++ b/CBPQ32.vcproj.SKIGACER.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/CommonCode.c b/CommonCode.c index 3b7fb70..48a253d 100644 --- a/CommonCode.c +++ b/CommonCode.c @@ -4859,7 +4859,6 @@ DllExport uint64_t APIENTRY GetPortFrequency(int PortNo, char * FreqString) struct TNCINFO * TNC; struct RIGINFO * RIG = 0; - int RigPort; if (PORT->RIGPort) TNC = TNCInfo[PORT->RIGPort]; @@ -5089,6 +5088,8 @@ void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT) int len; char * ptr; char mhstr[400]; + int i; + char c; if (MH == NULL) return; @@ -5110,7 +5111,16 @@ void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT) continue; } - Normcall[len++] = 0; + // validate call to prevent corruption of json + + for (i=0; i < len; i++) + { + c = Normcall[i]; + + if (!isalnum(c) && !(c == '#') && !(c == ' ') && !(c == '-')) + goto skipit; + } + //format TIME @@ -5123,7 +5133,7 @@ void BuildPortMH(char * MHJSON, struct PORTCONTROL * PORT) Normcall, PORT->PORTNUMBER, MH->MHCOUNT, MHTIME); strcat( MHJSON, mhstr ); - +skipit: MH++; } } diff --git a/HFCommon.c b/HFCommon.c index 00af093..c5f639a 100644 --- a/HFCommon.c +++ b/HFCommon.c @@ -1876,6 +1876,8 @@ int standardParams(struct TNCINFO * TNC, char * buf) TNC->WL2K = DecodeWL2KReportLine(buf); else if (_memicmp(buf, "SESSIONTIMELIMIT", 16) == 0) TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit = atoi(&buf[17]) * 60; + else if (_memicmp(buf, "ATTACHTIMELIMIT", 15) == 0) + TNC->AttachTimeLimit = atoi(&buf[16]) * 60; else if (_memicmp(buf, "BUSYHOLD", 8) == 0) // Hold Time for Busy Detect TNC->BusyHold = atoi(&buf[8]); else if (_memicmp(buf, "BUSYWAIT", 8) == 0) // Wait time before failing connect if busy diff --git a/HTTPcode.c b/HTTPcode.c index 367146d..e1ddfbe 100644 --- a/HTTPcode.c +++ b/HTTPcode.c @@ -600,7 +600,8 @@ VOID HTTPTimer() for (n = Last;;) { - strcat(_REPLYBUFFER, Session->ScreenLines[n]); + if ((strlen(Session->ScreenLines[n]) + strlen(_REPLYBUFFER)) < 99999) + strcat(_REPLYBUFFER, Session->ScreenLines[n]); if (n == 99) n = -1; @@ -680,13 +681,15 @@ struct HTTPConnectionInfo * FindSession(char * Key) void ProcessTermInput(SOCKET sock, char * MsgPtr, int MsgLen, char * Key) { - char _REPLYBUFFER[1024]; + char _REPLYBUFFER[2048]; int ReplyLen; char Header[256]; int HeaderLen; int State; struct HTTPConnectionInfo * Session = FindSession(Key); int Stream; + int maxlen = 1000; + if (Session == NULL) { @@ -701,12 +704,24 @@ void ProcessTermInput(SOCKET sock, char * MsgPtr, int MsgLen, char * Key) char c; UCHAR hex; + int msglen = end - input; + struct TNCINFO * TNC = Session->TNC; struct TCPINFO * TCP = 0; if (TNC) TCP = TNC->TCPInfo; + if (TCP && TCP->WebTermCSS) + maxlen -= strlen(TCP->WebTermCSS); + + if (MsgLen > maxlen) + { + Session->KillTimer = 99999; // close session + return; + } + + if (TCP && TCP->WebTermCSS) ReplyLen = sprintf(_REPLYBUFFER, InputLine, Key, TCP->WebTermCSS); else diff --git a/LinBPQ.c b/LinBPQ.c index 6146500..27dc550 100644 --- a/LinBPQ.c +++ b/LinBPQ.c @@ -1077,216 +1077,211 @@ int main(int argc, char * argv[]) BBSApplMask = 1<<(BBSApplNum-1); - // See if we need to warn of possible problem with BaseDir moved by installer + // See if we need to warn of possible problem with BaseDir moved by installer - sprintf(BaseDir, "%s", BPQDirectory); + sprintf(BaseDir, "%s", BPQDirectory); - // Set up file and directory names + // Set up file and directory names - strcpy(UserDatabasePath, BaseDir); - strcat(UserDatabasePath, "/"); - strcat(UserDatabasePath, UserDatabaseName); + strcpy(UserDatabasePath, BaseDir); + strcat(UserDatabasePath, "/"); + strcat(UserDatabasePath, UserDatabaseName); - strcpy(MsgDatabasePath, BaseDir); - strcat(MsgDatabasePath, "/"); - strcat(MsgDatabasePath, MsgDatabaseName); + strcpy(MsgDatabasePath, BaseDir); + strcat(MsgDatabasePath, "/"); + strcat(MsgDatabasePath, MsgDatabaseName); - strcpy(BIDDatabasePath, BaseDir); - strcat(BIDDatabasePath, "/"); - strcat(BIDDatabasePath, BIDDatabaseName); + strcpy(BIDDatabasePath, BaseDir); + strcat(BIDDatabasePath, "/"); + strcat(BIDDatabasePath, BIDDatabaseName); - strcpy(WPDatabasePath, BaseDir); - strcat(WPDatabasePath, "/"); - strcat(WPDatabasePath, WPDatabaseName); + strcpy(WPDatabasePath, BaseDir); + strcat(WPDatabasePath, "/"); + strcat(WPDatabasePath, WPDatabaseName); - strcpy(BadWordsPath, BaseDir); - strcat(BadWordsPath, "/"); - strcat(BadWordsPath, BadWordsName); + strcpy(BadWordsPath, BaseDir); + strcat(BadWordsPath, "/"); + strcat(BadWordsPath, BadWordsName); - strcpy(NTSAliasesPath, BaseDir); - strcat(NTSAliasesPath, "/"); - strcat(NTSAliasesPath, NTSAliasesName); + strcpy(NTSAliasesPath, BaseDir); + strcat(NTSAliasesPath, "/"); + strcat(NTSAliasesPath, NTSAliasesName); - strcpy(MailDir, BaseDir); - strcat(MailDir, "/"); - strcat(MailDir, "Mail"); + strcpy(MailDir, BaseDir); + strcat(MailDir, "/"); + strcat(MailDir, "Mail"); #ifdef WIN32 - CreateDirectory(MailDir, NULL); // Just in case + CreateDirectory(MailDir, NULL); // Just in case #else - mkdir(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); - chmod(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); + mkdir(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); + chmod(MailDir, S_IRWXU | S_IRWXG | S_IRWXO); #endif - // Make backup copies of Databases + // Make backup copies of Databases -// CopyConfigFile(ConfigName); + // CopyConfigFile(ConfigName); - CopyBIDDatabase(); - CopyMessageDatabase(); - CopyUserDatabase(); - CopyWPDatabase(); + CopyBIDDatabase(); + CopyMessageDatabase(); + CopyUserDatabase(); + CopyWPDatabase(); - SetupMyHA(); - SetupFwdAliases(); - SetupNTSAliases(NTSAliasesPath); + SetupMyHA(); + SetupFwdAliases(); + SetupNTSAliases(NTSAliasesPath); - GetWPDatabase(); + GetWPDatabase(); - GetMessageDatabase(); - GetUserDatabase(); - GetBIDDatabase(); - GetBadWordFile(); - GetHTMLForms(); - GetPGConfig(); + GetMessageDatabase(); + GetUserDatabase(); + GetBIDDatabase(); + GetBadWordFile(); + GetHTMLForms(); + GetPGConfig(); - // Make sure there is a user record for the BBS, with BBS bit set. + // Make sure there is a user record for the BBS, with BBS bit set. - user = LookupCall(BBSName); + user = LookupCall(BBSName); - if (user == NULL) - { - user = AllocateUserRecord(BBSName); - user->Temp = zalloc(sizeof (struct TempUserInfo)); - } - - if ((user->flags & F_BBS) == 0) - { - // Not Defined as a BBS - - if(SetupNewBBS(user)) - user->flags |= F_BBS; - } - - // if forwarding AMPR mail make sure User/BBS AMPR exists - - if (SendAMPRDirect) - { - BOOL NeedSave = FALSE; - - user = LookupCall("AMPR"); - if (user == NULL) { - user = AllocateUserRecord("AMPR"); + user = AllocateUserRecord(BBSName); user->Temp = zalloc(sizeof (struct TempUserInfo)); - NeedSave = TRUE; } if ((user->flags & F_BBS) == 0) { // Not Defined as a BBS - if (SetupNewBBS(user)) + if(SetupNewBBS(user)) user->flags |= F_BBS; - NeedSave = TRUE; } - if (NeedSave) - SaveUserDatabase(); - } + // if forwarding AMPR mail make sure User/BBS AMPR exists - - // Make sure SYSOPCALL is set - - if (SYSOPCall[0] == 0) - strcpy(SYSOPCall, BBSName); - - // See if just want to add user (mainly for setup scripts) - - if (argc == 5 && _stricmp(argv[1], "--adduser") == 0) - { - BOOL isBBS = FALSE; - char * response; - - if (_stricmp(argv[4], "TRUE") == 0) - isBBS = TRUE; - - printf("Adding User %s\r\n", argv[2]); - response = AddUser(argv[2], argv[3], isBBS); - printf("%s", response); - exit(0); - } - // Allocate Streams - - strcpy(pgm, "BBS"); - - for (i=0; i < MaxStreams; i++) - { - conn = &Connections[i]; - conn->BPQStream = FindFreeStream(); - - if (conn->BPQStream == 255) break; - - NumberofStreams++; - -// BPQSetHandle(conn->BPQStream, hWnd); - - SetAppl(conn->BPQStream, (i == 0 && EnableUI) ? 0x82 : 2, BBSApplMask); - Disconnect(conn->BPQStream); - } - - strcpy(pgm, "LINBPQ"); - - Debugprintf("POP3 Debug Before Init TCP Timer = %d", POP3Timer); - - InitialiseTCP(); - Debugprintf("POP3 Debug Before Init NNTP Timer = %d", POP3Timer); - InitialiseNNTP(); - - SetupListenSet(); // Master set of listening sockets - - if (EnableUI || MailForInterval) - SetupUIInterface(); - - if (MailForInterval) - _beginthread(SendMailForThread, 0, 0); - - - // Calulate time to run Housekeeping - { - struct tm *tm; - time_t now; - - now = time(NULL); - - tm = gmtime(&now); - - tm->tm_hour = MaintTime / 100; - tm->tm_min = MaintTime % 100; - tm->tm_sec = 0; - - MaintClock = mktime(tm) - (time_t)_MYTIMEZONE; - - while (MaintClock < now) - MaintClock += MaintInterval * 3600; - - Debugprintf("Maint Clock %lld NOW %lld Time to HouseKeeping %lld", (long long)MaintClock, (long long)now, (long long)(MaintClock - now)); - - if (LastHouseKeepingTime) + if (SendAMPRDirect) { - if ((now - LastHouseKeepingTime) > MaintInterval * 3600) + BOOL NeedSave = FALSE; + + user = LookupCall("AMPR"); + + if (user == NULL) { - DoHouseKeeping(FALSE); + user = AllocateUserRecord("AMPR"); + user->Temp = zalloc(sizeof (struct TempUserInfo)); + NeedSave = TRUE; } + + if ((user->flags & F_BBS) == 0) + { + // Not Defined as a BBS + + if (SetupNewBBS(user)) + user->flags |= F_BBS; + NeedSave = TRUE; + } + + if (NeedSave) + SaveUserDatabase(); } - for (i = optind; i < argc; i++) + + + // Make sure SYSOPCALL is set + + if (SYSOPCall[0] == 0) + strcpy(SYSOPCall, BBSName); + + // See if just want to add user (mainly for setup scripts) + + if (argc == 5 && _stricmp(argv[1], "--adduser") == 0) { - if (_stricmp(argv[i], "tidymail") == 0) - DeleteRedundantMessages(); + BOOL isBBS = FALSE; + char * response; - if (_stricmp(argv[i], "nohomebbs") == 0) - DontNeedHomeBBS = TRUE; + if (_stricmp(argv[4], "TRUE") == 0) + isBBS = TRUE; + + printf("Adding User %s\r\n", argv[2]); + response = AddUser(argv[2], argv[3], isBBS); + printf("%s", response); + exit(0); + } + // Allocate Streams + + strcpy(pgm, "BBS"); + + for (i=0; i < MaxStreams; i++) + { + conn = &Connections[i]; + conn->BPQStream = FindFreeStream(); + + if (conn->BPQStream == 255) break; + + NumberofStreams++; + + // BPQSetHandle(conn->BPQStream, hWnd); + + SetAppl(conn->BPQStream, (i == 0 && EnableUI) ? 0x82 : 2, BBSApplMask); + Disconnect(conn->BPQStream); } - printf("Mail Started\n"); - Logprintf(LOG_BBS, NULL, '!', "Mail Starting"); + strcpy(pgm, "LINBPQ"); - } - } + InitialiseTCP(); + InitialiseNNTP(); - Debugprintf("POP3 Debug After Mail Init Timer = %d", POP3Timer); + SetupListenSet(); // Master set of listening sockets + + if (EnableUI || MailForInterval) + SetupUIInterface(); + + if (MailForInterval) + _beginthread(SendMailForThread, 0, 0); + + + // Calulate time to run Housekeeping + { + struct tm *tm; + time_t now; + + now = time(NULL); + + tm = gmtime(&now); + + tm->tm_hour = MaintTime / 100; + tm->tm_min = MaintTime % 100; + tm->tm_sec = 0; + + MaintClock = mktime(tm) - (time_t)_MYTIMEZONE; + + while (MaintClock < now) + MaintClock += MaintInterval * 3600; + + Debugprintf("Maint Clock %lld NOW %lld Time to HouseKeeping %lld", (long long)MaintClock, (long long)now, (long long)(MaintClock - now)); + + if (LastHouseKeepingTime) + { + if ((now - LastHouseKeepingTime) > MaintInterval * 3600) + { + DoHouseKeeping(FALSE); + } + } + for (i = optind; i < argc; i++) + { + if (_stricmp(argv[i], "tidymail") == 0) + DeleteRedundantMessages(); + + if (_stricmp(argv[i], "nohomebbs") == 0) + DontNeedHomeBBS = TRUE; + } + + printf("Mail Started\n"); + Logprintf(LOG_BBS, NULL, '!', "Mail Starting"); + + } + } if (NUMBEROFTNCPORTS) InitializeTNCEmulator(); diff --git a/MHSave.txt b/MHSave.txt new file mode 100644 index 0000000..e69de29 diff --git a/MailNode.vcproj.NOTTSDESKTOP.John.user b/MailNode.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..34131b7 --- /dev/null +++ b/MailNode.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/MailNode.vcproj.SKIGACER.johnw.user b/MailNode.vcproj.SKIGACER.johnw.user new file mode 100644 index 0000000..b5b0536 --- /dev/null +++ b/MailNode.vcproj.SKIGACER.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/Moncode.c b/Moncode.c index aa1c0bd..6463b14 100644 --- a/Moncode.c +++ b/Moncode.c @@ -195,6 +195,9 @@ KC6OAR*>ID: // Check Port Port = msg->PORT; + + if (Port == 40) + Port = Port; if (Port & 0x80) { @@ -250,10 +253,8 @@ KC6OAR*>ID: ptr += 7; n--; - if (n == 0) - { + if (n < 0) return 0; // Corrupt - no end of address bit - } } // Reached End of digis diff --git a/SCSPactor.c.bak b/SCSPactor.c.bak deleted file mode 100644 index 78f96db..0000000 --- a/SCSPactor.c.bak +++ /dev/null @@ -1,4322 +0,0 @@ -/* -Copyright 2001-2022 John Wiseman G8BPQ - -This file is part of LinBPQ/BPQ32. - -LinBPQ/BPQ32 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 3 of the License, or -(at your option) any later version. - -LinBPQ/BPQ32 is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses -*/ - -// -// DLL to inteface SCS TNC in Pactor Mode to BPQ32 switch -// -// Uses BPQ EXTERNAL interface - - -// Dec 29 2009 - -// Add Scan Control using %W Hostmode Command -// Map Rig control port to a Virtual Serial Port. -// Add Support for packet port(s). - -// July 2010 - -// Support up to 32 BPQ Ports - -// Version 1.1.1.14 August 2010 - -// Drop RTS as well as DTR on close - -// Version 1.2.1.1 August 2010 - -// Save Minimized State - -// Version 1.2.1.2 August 2010 - -// Implement scan bandwidth change - -// Version 1.2.1.3 September 2010 - -// Don't connect if channel is busy -// Add WL2K reporting -// Add PACKETCHANNELS config command -// And Port Selector (P1 or P2) for Packet Ports - -// Version 1.2.1.4 September 2010 - -// Fix Freq Display after Node reconfig -// Only use AutoConnect APPL for Pactor Connects - -// Version 1.2.2.1 September 2010 - -// Add option to get config from bpq32.cfg - -// October 2011 - -// Changes for P4Dragon - -#define _CRT_SECURE_NO_WARNINGS -#define _CRT_SECURE_NO_DEPRECATE - - -#include -#include -#include "time.h" - -//#include -//#include - -#define MaxStreams 10 // First is used for Pactor, even though Pactor uses channel 31 - -#include "CHeaders.h" -#include "tncinfo.h" - -#include "bpq32.h" - -#ifndef WIN32 -#ifndef MACBPQ -#ifndef FREEBSD - -#include -#include -#endif -#endif -#endif - -static char ClassName[]="PACTORSTATUS"; -static char WindowTitle[] = "SCS Pactor"; -static int RigControlRow = 185; - - -#define NARROWMODE 12 // PI/II -#define WIDEMODE 16 // PIII only - -extern UCHAR LogDirectory[]; - -static RECT Rect; - -VOID __cdecl Debugprintf(const char * format, ...); - -char NodeCall[11]; // Nodecall, Null Terminated - -int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len); - -VOID SuspendOtherPorts(struct TNCINFO * ThisTNC); -VOID ReleaseOtherPorts(struct TNCINFO * ThisTNC); - -VOID PTCSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC); -VOID PTCReleasePort(struct TNCINFO * TNC); -int KissEncode(UCHAR * inbuff, UCHAR * outbuff, int len); -int CheckMode(struct TNCINFO * TNC); -VOID WritetoTrace(struct TNCINFO * TNC, char * Msg, int Len); -void SCSTryToSendDATA(struct TNCINFO * TNC, int Stream); -VOID UpdateMHwithDigis(struct TNCINFO * TNC, UCHAR * Call, char Mode, char Direction); -int standardParams(struct TNCINFO * TNC, char * buf); -int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length); - -#define FEND 0xC0 // KISS CONTROL CODES -#define FESC 0xDB -#define TFEND 0xDC -#define TFESC 0xDD - -static FILE * LogHandle[32] = {0}; - -//char * Logs[4] = {"1", "2", "3", "4"}; - -static char BaseDir[MAX_PATH]="c:\\"; - -static BOOL WRITELOG = FALSE; - -BOOL SCSStopPort(struct PORTCONTROL * PORT) -{ - // Disable Port - close TCP Sockets or Serial Port - - struct TNCINFO * TNC = PORT->TNC; - - TNC->CONNECTED = FALSE; - TNC->Alerted = FALSE; - - if (TNC->Streams[0].Attached) - TNC->Streams[0].ReportDISC = TRUE; - - if (TNC->hDevice) - { - CloseCOMPort(TNC->hDevice); - TNC->hDevice = 0; - } - - TNC->HostMode = FALSE; - - sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Stopped"); - MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE); - - return TRUE; -} - -BOOL SCSStartPort(struct PORTCONTROL * PORT) -{ - // Restart Port - Open Sockets or Serial Port - - struct TNCINFO * TNC = PORT->TNC; - - TNC->ReopenTimer = 999; // Reopen immediately - - sprintf(PORT->TNC->WEB_COMMSSTATE, "%s", "Port Restarted"); - MySetWindowText(PORT->TNC->xIDC_COMMSSTATE, PORT->TNC->WEB_COMMSSTATE); - - return TRUE; -} - - - -static VOID CloseLogFile(int Flags) -{ - if (WRITELOG) - { - fclose(LogHandle[Flags]); - LogHandle[Flags] = NULL; - } -} - -static BOOL OpenLogFile(int Flags) -{ - if (WRITELOG) - { - UCHAR FN[MAX_PATH]; - - time_t T; - struct tm * tm; - - T = time(NULL); - tm = gmtime(&T); - - sprintf(FN,"%s/logs/SCSLog_%02d%02d_%d.txt", LogDirectory, tm->tm_mon + 1, tm->tm_mday, Flags); - - LogHandle[Flags] = fopen(FN, "ab"); - - return (LogHandle[Flags] != NULL); - } - return 0; -} - -static void WriteLogLine(int Flags, char * Msg, int MsgLen) -{ - if (WRITELOG) - { - if (LogHandle[Flags]) - { - fwrite(Msg, 1, MsgLen, LogHandle[Flags]); - fwrite("\r\n", 1, 2, LogHandle[Flags]); - } - } -} - - -static int DontAddPDUPLEX = 0; - - -static int ProcessLine(char * buf, int Port) -{ - UCHAR * ptr,* p_cmd; - char * p_ipad = 0; - char * p_port = 0; - unsigned short WINMORport = 0; - int BPQport; - int len=510; - struct TNCINFO * TNC; - char errbuf[256]; - - BPQport = Port; - - TNC = TNCInfo[BPQport] = malloc(sizeof(struct TNCINFO)); - memset(TNC, 0, sizeof(struct TNCINFO)); - - TNC->InitScript = malloc(1000); - TNC->InitScript[0] = 0; - - goto ConfigLine; - - - // Read Initialisation lines - - while(TRUE) - { - if (GetLine(buf) == 0) - return TRUE; -ConfigLine: - - strcpy(errbuf, buf); - - if (memcmp(buf, "****", 4) == 0) - return TRUE; - - ptr = strchr(buf, ';'); - if (ptr) - { - *ptr++ = 13; - *ptr = 0; - } - - if (_memicmp(buf, "DEBUGLOG", 8) == 0) // Write Debug Log - WRITELOG = atoi(&buf[9]); - else - if (_memicmp(buf, "APPL", 4) == 0) - { - p_cmd = strtok(&buf[5], " \t\n\r"); - - if (p_cmd && p_cmd[0] != ';' && p_cmd[0] != '#') - TNC->ApplCmd=_strdup(_strupr(p_cmd)); - } - else - if (_memicmp(buf, "PACKETCHANNELS", 14) == 0) // Packet Channels - TNC->PacketChannels = atoi(&buf[14]); - - else - if (_memicmp(buf, "SCANFORROBUSTPACKET", 19) == 0) - { - // Spend a percentage of scan time in Robust Packet Mode - - double Robust = atof(&buf[20]); - #pragma warning(push) - #pragma warning(disable : 4244) - TNC->RobustTime = Robust * 10; - #pragma warning(pop) - } - else - if (_memicmp(buf, "USEAPPLCALLS", 12) == 0 && buf[12] != 'F' && buf[12] != 'f') - TNC->UseAPPLCalls = TRUE; - else - if (_memicmp(buf, "USEAPPLCALLSFORPACTOR", 21) == 0) - TNC->UseAPPLCallsforPactor = TRUE; - else - if (_memicmp(buf, "DRAGON", 6) == 0) - { - TNC->Dragon = TRUE; - if (_memicmp(&buf[7], "SINGLE", 6) == 0) - TNC->DragonSingle = TRUE; - - if (_memicmp(&buf[7], "KISS", 4) == 0) - TNC->DragonKISS = TRUE; - } - else - if (_memicmp(buf, "DEFAULT ROBUST", 14) == 0) - TNC->RobustDefault = TRUE; - else - if (_memicmp(buf, "DontAddPDUPLEX", 14) == 0) - DontAddPDUPLEX = TRUE; - else - if (_memicmp(buf, "FORCE ROBUST", 12) == 0) - TNC->ForceRobust = TNC->RobustDefault = TRUE; - else - if (_memicmp(buf, "MAXLEVEL", 8) == 0) // Maximum Pactor Level to use. - TNC->MaxLevel = atoi(&buf[8]); - else - if (_memicmp(buf, "DATE", 4) == 0) - { - char Cmd[32]; - time_t T; - struct tm * tm; - - T = time(NULL); - tm = gmtime(&T); - - sprintf(Cmd,"DATE %02d%02d%02d\r", tm->tm_mday, tm->tm_mon + 1, tm->tm_year - 100); - - strcat (TNC->InitScript, Cmd); - } - else if (_memicmp(buf, "TIME", 4) == 0) - { - char Cmd[32]; - time_t T; - struct tm * tm; - - T = time(NULL); - tm = gmtime(&T); - - sprintf(Cmd,"TIME %02d%02d%02d\r", tm->tm_hour, tm->tm_min, tm->tm_sec); - - strcat (TNC->InitScript, Cmd); - } - else if (standardParams(TNC, buf) == FALSE) - strcat (TNC->InitScript, buf); - } - - return (TRUE); - -} - -struct TNCINFO * CreateTTYInfo(int port, int speed); - -BOOL CloseConnection(struct TNCINFO * conn); -BOOL WriteCommBlock(struct TNCINFO * TNC); -BOOL DestroyTTYInfo(int port); -void SCSCheckRX(struct TNCINFO * TNC); -VOID SCSPoll(int Port); -VOID CRCStuffAndSend(struct TNCINFO * TNC, UCHAR * Msg, int Len); -unsigned short int compute_crc(unsigned char *buf,int len); -int Unstuff(UCHAR * MsgIn, UCHAR * MsgOut, int len); -VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * rxbuff, int len); -VOID ProcessTermModeResponse(struct TNCINFO * TNC); -static VOID ExitHost(struct TNCINFO * TNC); -static VOID DoTNCReinit(struct TNCINFO * TNC); -static VOID DoTermModeTimeout(struct TNCINFO * TNC); -static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len); -int Switchmode(struct TNCINFO * TNC, int Mode); -VOID SwitchToPactor(struct TNCINFO * TNC); -VOID SwitchToPacket(struct TNCINFO * TNC); - - -char status[8][8] = {"ERROR", "REQUEST", "TRAFFIC", "IDLE", "OVER", "PHASE", "SYNCH", ""}; - -char ModeText[8][14] = {"STANDBY", "AMTOR-ARQ", "PACTOR-ARQ", "AMTOR-FEC", "PACTOR-FEC", "RTTY / CW", "LISTEN", "Channel-Busy"}; - -char PactorLevelText[5][14] = {"Not Connected", "PACTOR-I", "PACTOR-II", "PACTOR-III", "PACTOR-IV"}; - -char PleveltoMode[5] = {30, 11, 14, 16, 20}; // WL2K Reporting Modes - RP, P1, P2, P3, P4 - - -static size_t ExtProc(int fn, int port, PDATAMESSAGE buff) -{ - int txlen = 0; - PMSGWITHLEN buffptr; - struct TNCINFO * TNC = TNCInfo[port]; - size_t Param; - int Stream = 0; - struct STREAMINFO * STREAM = &TNC->Streams[0]; - char PLevel; - struct ScanEntry * Scan; - - if (TNC == NULL) - return 0; - - if (TNC->hDevice == 0) - { - // Clear anything from UI_Q - - while (TNC->PortRecord->UI_Q) - { - buffptr = Q_REM(&TNC->PortRecord->UI_Q); - ReleaseBuffer(buffptr); - } - - // Try to reopen every 30 secs - - if (fn > 3 && fn < 7) - goto ok; - - TNC->ReopenTimer++; - - if (TNC->ReopenTimer < 300) - return 0; - - TNC->ReopenTimer = 0; - - if (TNC->PortRecord->PORTCONTROL.PortStopped == 0) - OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE); - - if (TNC->hDevice == 0) - return 0; - -#ifndef WIN32 -#ifndef MACBPQ -#ifndef FREEBSD - - if (TNC->Dragon) - { - struct serial_struct sstruct; - - // Need to set custom baud rate - - if (ioctl(TNC->hDevice, TIOCGSERIAL, &sstruct) < 0) - { - Debugprintf("Error: Dragon could not get comm ioctl\n"); - } - else - { - // set custom divisor to get 829440 baud - - sstruct.custom_divisor = 29; - sstruct.flags |= ASYNC_SPD_CUST; - - // set serial_struct - - if (ioctl(TNC->hDevice, TIOCSSERIAL, &sstruct) < 0) - Debugprintf("Error: Dragon could not set custom comm baud divisor\n"); - else - Debugprintf("Dragon custom baud rate set\n"); - } - } -#endif -#endif -#endif - - } -ok: - switch (fn) - { - case 7: - - // 100 mS Timer. May now be needed, as Poll can be called more frequently in some circumstances - - // G7TAJ's code to record activity for stats display - - if ( TNC->BusyFlags && CDBusy ) - TNC->PortRecord->PORTCONTROL.ACTIVE += 2; - - if ( TNC->PTTState ) - TNC->PortRecord->PORTCONTROL.SENDING += 2; - - SCSCheckRX(TNC); - SCSPoll(port); - - return 0; - - case 1: // poll - - // Check session limit timer - - if ((STREAM->Connecting || STREAM->Connected) && !STREAM->Disconnecting) - { - if (TNC->SessionTimeLimit && STREAM->ConnectTime && time(NULL) > (TNC->SessionTimeLimit + STREAM->ConnectTime)) - { - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - sprintf(STREAM->CmdSet, "D\r"); - STREAM->Disconnecting = TRUE; - } - } - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->Streams[Stream].ReportDISC) - { - TNC->Streams[Stream].ReportDISC = FALSE; - buff->PORT = Stream; - - return -1; - } - } - - if (TNC->EnterExit) - return 0; // Switching to Term mode to change bandwidth - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->Streams[Stream].PACTORtoBPQ_Q !=0) - { - int datalen; - - buffptr = Q_REM(&TNC->Streams[Stream].PACTORtoBPQ_Q); - datalen = (int)buffptr->Len; - - buff->PORT = Stream; // Compatibility with Kam Driver - buff->PID = 0xf0; - memcpy(&buff->L2DATA, &buffptr->Data[0], datalen); // Data goes to + 7, but we have an extra byte - datalen += sizeof(void *) + 4; - - PutLengthinBuffer(buff, datalen); - - ReleaseBuffer(buffptr); - - return (1); - } - } - - return 0; - - case 2: // send - - buffptr = GetBuff(); - - if (buffptr == 0) return 0; // No buffers, so ignore - - Stream = buff->PORT; - - if (!TNC->TNCOK) - { - // Send Error Response - - buffptr->Len = sprintf(buffptr->Data, "No Connection to PACTOR TNC\r"); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return 0; - } - - txlen = GetLengthfromBuffer(buff) - (MSGHDDRLEN + 1); // 1 as no PID - - if (txlen == 1 && buff->L2DATA[0] == 0) // Keepalive Packet - { - ReleaseBuffer(buffptr); - return 0; - } - - buffptr->Len = txlen; - memcpy(buffptr->Data, buff->L2DATA, txlen); - - C_Q_ADD(&TNC->Streams[Stream].BPQtoPACTOR_Q, buffptr); - - TNC->Streams[Stream].FramesOutstanding++; - - // See if possible to send immediately - - SCSTryToSendDATA(TNC, Stream); - - return 0; - - case 3: // CHECK IF OK TO SEND. Also used to check if TNC is responding - - Stream = (int)(size_t)buff; - - STREAM = &TNC->Streams[Stream]; - - if (Stream == 0) - { - if (TNC->Dragon) - { - if (STREAM->FramesOutstanding > 25) - return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15); - } - else - { - if (STREAM->FramesOutstanding > 10) - return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15); - } - } - else - { - if (STREAM->FramesOutstanding > 3 || TNC->Buffers < 200) - return (1 | TNC->HostMode << 8 | STREAM->Disconnecting << 15); } - - return TNC->HostMode << 8 | STREAM->Disconnecting << 15; // OK, but lock attach if disconnecting - - - case 4: // reinit - - // Ensure in Pactor - - TNC->TXBuffer[2] = 31; - TNC->TXBuffer[3] = 0x1; - TNC->TXBuffer[4] = 0x1; - memcpy(&TNC->TXBuffer[5], "PT", 2); - - CRCStuffAndSend(TNC, TNC->TXBuffer, 7); - - Sleep(25); - ExitHost(TNC); - Sleep(50); - CloseCOMPort(TNC->hDevice); - TNC->hDevice =(HANDLE)0; - TNC->ReopenTimer = 250; - TNC->HostMode = FALSE; - - return (0); - - case 5: // Close - - // Ensure in Pactor - - TNC->TXBuffer[2] = 31; - TNC->TXBuffer[3] = 0x1; - TNC->TXBuffer[4] = 0x1; - memcpy(&TNC->TXBuffer[5], "PT", 2); - - CRCStuffAndSend(TNC, TNC->TXBuffer, 7); - - Sleep(25); - - ExitHost(TNC); - - Sleep(25); - - CloseCOMPort(TNCInfo[port]->hDevice); - - return (0); - - case 6: // Scan Interface - - Param = (size_t)buff; - - switch (Param) - { - case 1: // Request Permission - - if (TNC->TNCOK) - { - // If been in Sync a long time, or if using applcalls and - // Scan had been locked too long just let it change - - if (TNC->UseAPPLCallsforPactor) - { - if (TNC->PTCStatus == 6) // Sync - { - int insync = (int)(time(NULL) - TNC->TimeEnteredSYNCMode); - if (insync > 4) - { - Debugprintf("SCS Scan - in SYNC for %d Secs - allow change regardless", insync); - return 0; - } - } - else if (TNC->TimeScanLocked) - { - time_t timeLocked = time(NULL) - TNC->TimeScanLocked; - if (timeLocked > 4) - { - Debugprintf("SCS Scan - Scan Locked for %d Secs - allow change regardless", timeLocked); - TNC->TimeScanLocked = 0; - return 0; - } - } - } - - TNC->WantToChangeFreq = TRUE; - TNC->OKToChangeFreq = FALSE; - return TRUE; - } - return 0; // Don't lock scan if TNC isn't responding - - - case 2: // Check Permission - return TNC->OKToChangeFreq; - - case 3: // Release Permission - - TNC->WantToChangeFreq = FALSE; - - if (TNC->DontReleasePermission) // Disable connects during this interval? - { - TNC->DontReleasePermission = FALSE; - if (TNC->SyncSupported == FALSE) - TNC->TimeScanLocked = time(NULL) + 100; // Make sure doesnt time out - return 0; - } - - TNC->DontWantToChangeFreq = TRUE; - return 0; - - default: // Param is Address of a struct ScanEntry - - Scan = (struct ScanEntry *)buff; - - PLevel = Scan->PMaxLevel; - - if (PLevel == 0 && (Scan->HFPacketMode || Scan->RPacketMode)) - { - // Switch to Packet for this Interval - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("SCS Switching to Packet, %d", TNC->HFPacket); - - if (TNC->HFPacket == FALSE) - SwitchToPacket(TNC); - - return 0; - } - - if (PLevel > '0' && PLevel < '5') // 1 - 4 - { - if (TNC->Bandwidth != PLevel || TNC->MinLevel != (Scan->PMinLevel - '0')) - { - TNC->Bandwidth = PLevel; - TNC->MinLevel = Scan->PMinLevel - '0'; - Switchmode(TNC, PLevel - '0'); - } - - if (TNC->UseAPPLCallsforPactor && Scan->APPLCALL[0]) - { - // Switch callsign - - STREAM = &TNC->Streams[0]; - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - - strcpy(STREAM->MyCall, Scan->APPLCALL); - - sprintf(STREAM->CmdSet, "I%s\rI\r", STREAM->MyCall); - if (TNC->RIG->RIG_DEBUG) - Debugprintf("SCS Pactor APPLCALL Set to %s", STREAM->MyCall); - } - - else - { - if (TNC->HFPacket) - SwitchToPactor(TNC); - } - } - - if (Scan->RPacketMode) - if (TNC->RobustTime) - SwitchToPacket(TNC); // Always start in packet, switch to pactor after RobustTime ticks - - if (PLevel == '0') - TNC->DontReleasePermission = TRUE; // Dont allow connects in this interval - else - TNC->DontReleasePermission = FALSE; - - return 0; - } - } - return 0; -} - -int DoScanLine(struct TNCINFO * TNC, char * Buff, int Len) -{ - struct RIGINFO * RIG = TNC->RIG; - - if (RIG && RIG->WEB_Label) - { - Len += sprintf(&Buff[Len], ""); - Len += sprintf(&Buff[Len], "", RIG->WEB_Label); - Len += sprintf(&Buff[Len], "", RIG->WEB_FREQ); - Len += sprintf(&Buff[Len], "", RIG->WEB_MODE); - Len += sprintf(&Buff[Len], "", RIG->WEB_SCAN); - Len += sprintf(&Buff[Len], "", RIG->WEB_PTT); - - - if (TNC->TXRIG && TNC->TXRIG != TNC->RIG) - { - struct RIGINFO * RIG = TNC->TXRIG; - - Len += sprintf(&Buff[Len], "", RIG->WEB_Label); - Len += sprintf(&Buff[Len], "", RIG->WEB_FREQ); - Len += sprintf(&Buff[Len], "", RIG->WEB_MODE); - Len += sprintf(&Buff[Len], "", RIG->WEB_SCAN); - Len += sprintf(&Buff[Len], "
%s%s%s%c%c
%s%s%s%c%c
", RIG->WEB_PTT); - } - Len += sprintf(&Buff[Len], ""); - } - return Len; -} - -static int WebProc(struct TNCINFO * TNC, char * Buff, BOOL LOCAL) -{ - int Len = sprintf(Buff, "" - "SCS Pactor Status

SCS Pactor Status

"); - - Len += sprintf(&Buff[Len], ""); - - Len += sprintf(&Buff[Len], "", TNC->WEB_COMMSSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TNCSTATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_MODE); - Len += sprintf(&Buff[Len], "", TNC->WEB_STATE); - Len += sprintf(&Buff[Len], "", TNC->WEB_TXRX); - Len += sprintf(&Buff[Len], "", TNC->WEB_BUFFERS); - Len += sprintf(&Buff[Len], "", TNC->WEB_TRAFFIC); - Len += sprintf(&Buff[Len], "", TNC->WEB_PACTORLEVEL); - Len += sprintf(&Buff[Len], "
Comms State%s
TNC State%s
Mode%s
Status%s
TX/RX State%s
Buffers%s
Traffic%s
Mode%s
"); - - Len += sprintf(&Buff[Len], "", TNC->WebBuffer); - Len = DoScanLine(TNC, Buff, Len); - - return Len; -} - -void * SCSExtInit(EXTPORTDATA * PortEntry) -{ - char msg[500]; - struct TNCINFO * TNC; - int port; - char * ptr; - int Stream = 0; - char * TempScript; - - // - // Will be called once for each Pactor Port - // The COM port number is in IOBASE - // - - DontAddPDUPLEX = 0; - - sprintf(msg,"SCS Pactor %s", PortEntry->PORTCONTROL.SerialPortName); - WritetoConsole(msg); - - port=PortEntry->PORTCONTROL.PORTNUMBER; - - ReadConfigFile(port, ProcessLine); - - TNC = TNCInfo[port]; - - if (TNC == NULL) - { - // Not defined in Config file - - sprintf(msg," ** Error - no info in BPQ32.cfg for this port\n"); - WritetoConsole(msg); - - return ExtProc; - } - - TNC->Port = port; - TNC->Hardware = H_SCS; - - OpenLogFile(TNC->Port); - CloseLogFile(TNC->Port); - - - if (TNC->BusyHold == 0) - TNC->BusyHold = 3; - - if (TNC->BusyWait == 0) - TNC->BusyWait = 10; - - if (TNC->MaxLevel == 0) - TNC->MaxLevel = 3; - - // Set up DED addresses for streams (first stream (Pactor) = DED 31 - - TNC->Streams[0].DEDStream = 31; - - for (Stream = 1; Stream <= MaxStreams; Stream++) - { - TNC->Streams[Stream].DEDStream = Stream; - } - - if (TNC->PacketChannels > MaxStreams) - TNC->PacketChannels = MaxStreams; - - PortEntry->MAXHOSTMODESESSIONS = TNC->PacketChannels + 1; - PortEntry->PERMITGATEWAY = TRUE; // Can change ax.25 call on each stream - PortEntry->SCANCAPABILITIES = CONLOCK; // Scan Control 3 stage/conlock - - TNC->PortRecord = PortEntry; - - if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0) - TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK; - - if (PortEntry->PORTCONTROL.PORTCALL[0] == 0) - memcpy(TNC->NodeCall, MYNODECALL, 10); - else - ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall); - - PortEntry->PORTCONTROL.PROTOCOL = 10; - PortEntry->PORTCONTROL.PORTQUALITY = 0; - - if (PortEntry->PORTCONTROL.PORTPACLEN == 0) - PortEntry->PORTCONTROL.PORTPACLEN = 100; - - TNC->SuspendPortProc = PTCSuspendPort; - TNC->ReleasePortProc = PTCReleasePort; - - PortEntry->PORTCONTROL.PORTSTARTCODE = SCSStartPort; - PortEntry->PORTCONTROL.PORTSTOPCODE = SCSStopPort; - - PortEntry->PORTCONTROL.UICAPABLE = TRUE; - - ptr=strchr(TNC->NodeCall, ' '); - if (ptr) *(ptr) = 0; // Null Terminate - - // get NODECALL for RP tests - - memcpy(NodeCall, MYNODECALL, 10); - - ptr=strchr(NodeCall, ' '); - if (ptr) *(ptr) = 0; // Null Terminate - - - // Set TONES to 4 - - TempScript = malloc(1000); - - strcpy(TempScript, "QUIT\r"); // In case in pac: mode - strcat(TempScript, "TONES 4\r"); // Tones may be changed but I want this as standard - strcat(TempScript, "MAXERR 30\r"); // Max retries - strcat(TempScript, "MODE 0\r"); // ASCII mode, no PTC II compression (Forwarding will use FBB Compression) - strcat(TempScript, "MAXSUM 20\r"); // Max count for memory ARQ - strcat(TempScript, "CWID 0 2\r"); // CW ID disabled - strcat(TempScript, "PTCC 0\r"); // Dragon out of PTC Compatibility Mode - strcat(TempScript, "VER\r"); // Try to determine Controller Type - - sprintf(msg, "MYLEVEL %d\r", TNC->MaxLevel); - strcat(TempScript, msg); // Default Level to MAXLEVEL - - strcat(TempScript, TNC->InitScript); - - free(TNC->InitScript); - TNC->InitScript = TempScript; - - // Others go on end so they can't be overriden - - strcat(TNC->InitScript, "ADDLF 0\r"); // Auto Line Feed disabled - strcat(TNC->InitScript, "ARX 0\r"); // Amtor Phasing disabled - strcat(TNC->InitScript, "BELL 0\r"); // Disable Bell - strcat(TNC->InitScript, "BC 0\r"); // FEC reception is disabled - strcat(TNC->InitScript, "BKCHR 2\r"); // Breakin Char = 2 - strcat(TNC->InitScript, "CHOBELL 0\r"); // Changeover Bell off - strcat(TNC->InitScript, "CMSG 0\r"); // Connect Message Off - strcat(TNC->InitScript, "LFIGNORE 0\r"); // No insertion of Line feed - strcat(TNC->InitScript, "LISTEN 0\r"); // Pactor Listen disabled - strcat(TNC->InitScript, "MAIL 0\r"); // Disable internal mailbox reporting - strcat(TNC->InitScript, "REMOTE 0\r"); // Disable remote control - strcat(TNC->InitScript, "PAC CBELL 0\r"); // - strcat(TNC->InitScript, "PAC CMSG 0\r"); // - strcat(TNC->InitScript, "PAC PRBOX 0\r"); // Turn off Packet Radio Mailbox - - // Automatic Status must be enabled for BPQ32 - // Pactor must use Host Mode Chanel 31 - // PDuplex must be set. The Node code relies on automatic IRS/ISS changeover - // 5 second duplex timer - - strcat(TNC->InitScript, "STATUS 2\rPTCHN 31\rPDTIMER 5\r"); - - if (DontAddPDUPLEX == 0) - strcat(TNC->InitScript, "PDUPLEX 1\r"); - - sprintf(msg, "MYCALL %s\rPAC MYCALL %s\r", TNC->NodeCall, TNC->NodeCall); - strcat(TNC->InitScript, msg); - - PortEntry->PORTCONTROL.TNC = TNC; - - TNC->WebWindowProc = WebProc; - TNC->WebWinX = 510; - TNC->WebWinY = 280; - - TNC->WEB_COMMSSTATE = zalloc(100); - TNC->WEB_TNCSTATE = zalloc(100); - strcpy(TNC->WEB_TNCSTATE, "Free"); - TNC->WEB_MODE = zalloc(100); - TNC->WEB_TRAFFIC = zalloc(100); - TNC->WEB_BUFFERS = zalloc(100); - TNC->WEB_STATE = zalloc(100); - TNC->WEB_TXRX = zalloc(100); - TNC->WEB_PACTORLEVEL = zalloc(100); - TNC->WebBuffer = zalloc(5000); - - -#ifndef LINBPQ - - CreatePactorWindow(TNC, ClassName, WindowTitle, RigControlRow, PacWndProc, 500, 500, ForcedClose); - - CreateWindowEx(0, "STATIC", "Comms State", WS_CHILD | WS_VISIBLE, 10,6,120,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_COMMSSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,6,386,20, TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "TNC State", WS_CHILD | WS_VISIBLE, 10,28,106,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_TNCSTATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,28,520,20, TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE, 10,50,80,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_MODE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,50,200,20, TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "Status", WS_CHILD | WS_VISIBLE, 10,72,110,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_STATE = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE, 116,72,144,20, TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "TX/RX State", WS_CHILD | WS_VISIBLE,10,94,80,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_TXRX = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,94,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "Buffers", WS_CHILD | WS_VISIBLE,10,116,80,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_BUFFERS = CreateWindowEx(0, "STATIC", "", WS_CHILD | WS_VISIBLE,116,116,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - CreateWindowEx(0, "STATIC", "Traffic", WS_CHILD | WS_VISIBLE,10,138,80,20, TNC->hDlg, NULL, hInstance, NULL); - TNC->xIDC_TRAFFIC = CreateWindowEx(0, "STATIC", "RX 0 TX 0 ACKED 0", WS_CHILD | WS_VISIBLE,116,138,374,20 , TNC->hDlg, NULL, hInstance, NULL); - - TNC->xIDC_PACTORLEVEL = CreateWindowEx(0, "STATIC", "Mode", WS_CHILD | WS_VISIBLE,10,160,430,20, TNC->hDlg, NULL, hInstance, NULL); - - TNC->hMonitor= CreateWindowEx(0, "LISTBOX", "", WS_CHILD | WS_VISIBLE | LBS_NOINTEGRALHEIGHT | - LBS_DISABLENOSCROLL | WS_HSCROLL | WS_VSCROLL, - 0,RigControlRow + 44,250,300, TNC->hDlg, NULL, hInstance, NULL); - - TNC->ClientHeight = 500; - TNC->ClientWidth = 500; - - sprintf(TNC->WEB_BUFFERS, "%05d Queued %05d", TNC->Buffers, TNC->Streams[0].FramesOutstanding); - SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS); - - - MoveWindows(TNC); -#endif - OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE); - -#ifndef WIN32 -#ifndef MACBPQ -#ifndef FREEBSD - - if (TNC->Dragon) - { - struct serial_struct sstruct; - - // Need to set custom baud rate - - if (ioctl(TNC->hDevice, TIOCGSERIAL, &sstruct) < 0) - { - printf("Error: Dragon could not get comm ioctl\n"); - } - else - { - // set custom divisor to get 829440 baud - - sstruct.custom_divisor = 29; - sstruct.flags |= ASYNC_SPD_CUST; - - // set serial_struct - - if (ioctl(TNC->hDevice, TIOCSSERIAL, &sstruct) < 0) - Debugprintf("Error: Dragon could not set custom comm baud divisor\n"); - else - Debugprintf("Dragon custom baud rate set\n"); - } - } -#endif -#endif -#endif - if (TNC->RobustDefault) - SwitchToPacket(TNC); - - WritetoConsole("\n"); - - return ExtProc; -} - -void SCSCheckRX(struct TNCINFO * TNC) -{ - int Length, Len; - unsigned short crc; - char UnstuffBuffer[500]; - - if (TNC->RXLen == 500) - TNC->RXLen = 0; - - Len = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen); - - if (Len == 0) - return; - - TNC->RXLen += Len; - - Length = TNC->RXLen; - - // DED mode doesn't have an end of frame delimiter. We need to know if we have a full frame - - // Fortunately this is a polled protocol, so we only get one frame at a time - - // If first char != 170, then probably a Terminal Mode Frame. Wait for CR on end - - // If first char is 170, we could check rhe length field, but that could be corrupt, as - // we haen't checked CRC. All I can think of is to check the CRC and if it is ok, assume frame is - // complete. If CRC is duff, we will eventually time out and get a retry. The retry code - // can clear the RC buffer - - if (TNC->UsingTermMode) - { - // Send response to Host if connected - - PMSGWITHLEN buffptr; - int Len = TNC->RXLen; - int Posn = 0; - - // First message is probably ACK of JHO4T - AA AA 1F 00 1E 19 - - if (TNC->RXBuffer[0] == 0xaa && Len > 6) - { - memmove(TNC->RXBuffer, &TNC->RXBuffer[6], Len - 6); - Len -= 6; - } - - // TNC seems to send 1e f7 or 1e 87 regularly - - while (TNC->RXBuffer[0] == 0x1e && Len > 1) - { - memmove(TNC->RXBuffer, &TNC->RXBuffer[2], Len - 2); - Len -= 2; - } - - if (Len == 0) - { - TNC->RXLen = 0; // Ready for next frame - return; - } - - while (Len > 250) - { - buffptr = GetBuff(); - buffptr->Len = 250; - memcpy(buffptr->Data, &TNC->RXBuffer[Posn], 250); - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - Len -= 250; - Posn += 250; - } - - buffptr = GetBuff(); - buffptr->Len = Len; - memcpy(buffptr->Data, &TNC->RXBuffer[Posn], Len); - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - - TNC->RXLen = 0; // Ready for next frame - return; - } - - - if (TNC->RXBuffer[0] != 170) - { - // Char Mode Frame I think we need to see cmd: on end - - // If we think we are in host mode, then to could be noise - just discard. - - if (TNC->HostMode) - { - TNC->RXLen = 0; // Ready for next frame - return; - } - - TNC->RXBuffer[TNC->RXLen] = 0; - -// if (TNC->Streams[Stream].RXBuffer[TNC->Streams[Stream].RXLen-2] != ':') - - if (strlen(TNC->RXBuffer) < TNC->RXLen) - TNC->RXLen = 0; - - if ((strstr(TNC->RXBuffer, "cmd: ") == 0) && (strstr(TNC->RXBuffer, "pac: ") == 0)) - - return; // Wait for rest of frame - - // Complete Char Mode Frame - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, TNC->RXBuffer, (int)strlen(TNC->RXBuffer)); - CloseLogFile(TNC->Port); - - TNC->RXLen = 0; // Ready for next frame - - if (TNC->HostMode == 0) - { - // We think TNC is in Terminal Mode - ProcessTermModeResponse(TNC); - return; - } - // We thought it was in Host Mode, but are wrong. - - TNC->HostMode = FALSE; - return; - } - - // Receiving a Host Mode frame - - if (Length < 6) // Minimum Frame Sise - return; - - if (TNC->RXBuffer[2] == 170) - { - // Retransmit Request - - TNC->RXLen = 0; - return; // Ignore for now - } - - // Can't unstuff into same buffer - fails if partial msg received, and we unstuff twice - - - Length = Unstuff(&TNC->RXBuffer[2], &UnstuffBuffer[2], Length - 2); - - if (Length == -1) - { - // Unstuff returned an errors (170 not followed by 0) - - TNC->RXLen = 0; - return; // Ignore for now - } - crc = compute_crc(&UnstuffBuffer[2], Length); - - if (crc == 0xf0b8) // Good CRC - { - TNC->RXLen = 0; // Ready for next frame - ProcessDEDFrame(TNC, UnstuffBuffer, Length); - - // If there are more channels to poll (more than 1 entry in general poll response, - // and link is not active, poll the next one - - if (TNC->Timeout == 0) - { - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->NexttoPoll[0]) - { - UCHAR Chan = TNC->NexttoPoll[0] - 1; - - memmove(&TNC->NexttoPoll[0], &TNC->NexttoPoll[1], 19); - - Poll[2] = Chan; // Channel - Poll[3] = 0x1; // Command - - if (Chan == 254) // Status - Send Extended Status (G3) - { - Poll[4] = 1; // Len-1 - Poll[5] = 'G'; // Extended Status Poll - Poll[6] = '3'; - } - else - { - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - } - - CRCStuffAndSend(TNC, Poll, Poll[4] + 6); - TNC->InternalCmd = FALSE; - - return; - } - else - { - // if last message wasn't a general poll, send one now - - if (TNC->PollSent) - return; - - TNC->PollSent = TRUE; - - // Use General Poll (255) - - Poll[2] = 255 ; // Channel - Poll[3] = 0x1; // Command - - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - - CRCStuffAndSend(TNC, Poll, 6); - TNC->InternalCmd = FALSE; - } - } - return; - } - - // Bad CRC - assume incomplete frame, and wait for rest. If it was a full bad frame, timeout and retry will recover link. - - return; -} - -BOOL WriteCommBlock(struct TNCINFO * TNC) -{ - BOOL ret = WriteCOMBlock(TNC, TNC->TXBuffer, TNC->TXLen); - - TNC->Timeout = 20; // 2 secs - return ret; -} - -VOID SCSPoll(int Port) -{ - struct TNCINFO * TNC = TNCInfo[Port]; - UCHAR * Poll = TNC->TXBuffer; - char Status[80]; - int Stream = 0; - int nn; - struct STREAMINFO * STREAM; - - if (TNC->UsingTermMode) - { - if (TNC->Streams[Stream].BPQtoPACTOR_Q) - { - PMSGWITHLEN buffptr = Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q); - - // See if enter host mode command - - if (_memicmp(buffptr->Data, "ENTERHOST\r", buffptr->Len) == 0) - { - TNC->UsingTermMode = FALSE; - - memcpy(Poll, "JHOST4\r", 7); - TNC->TXLen = 7; - WriteCommBlock(TNC); - - // No response expected - - Sleep(10); - - Poll[2] = 255; // Channel - TNC->Toggle = 0; - Poll[3] = 0x41; - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - - CRCStuffAndSend(TNC, Poll, 6); - TNC->InternalCmd = FALSE; - TNC->Timeout = 5; // 1/2 sec - In case missed - - - } - else - { - // Send to TNC - - memcpy(&Poll[0], buffptr->Data, buffptr->Len); - TNC->TXLen = buffptr->Len;; - WriteCommBlock(TNC); - } - ReleaseBuffer(buffptr); - } - return; - } - - if (TNC->MinLevelTimer) - { - TNC->MinLevelTimer--; - - if (TNC->MinLevelTimer == 0) - { - // Failed to reach min level in 15 secs - - STREAM = &TNC->Streams[0]; - - if (STREAM->Connected) - { - PMSGWITHLEN buffptr; - - Debugprintf("Required Min Level not reached - disconnecting"); - - // Discard Queued Data, Send a Message, then a disconnect - - while (STREAM->BPQtoPACTOR_Q) - ReleaseBuffer(Q_REM(&STREAM->BPQtoPACTOR_Q)); - - STREAM->NeedDisc = 15; // 1 secs - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = sprintf(buffptr->Data, - "This port only allows Pactor Level %d or above - Disconnecting\r\n", TNC->MinLevel); - - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - } - } - } - - if (TNC->SwitchToPactor) - { - TNC->SwitchToPactor--; - - if (TNC->SwitchToPactor == 0) - SwitchToPactor(TNC); - } - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && TNC->Streams[Stream].Attached == 0) - { - // New Attach - - // If Pactor, stop scanning and take out of listen mode. - - // Set call to connecting user's call - - // If Stream 0 Put in Pactor Mode so Busy Detect will work - - int calllen=0; - - STREAM = &TNC->Streams[Stream]; - Debugprintf("SCS New Attach Stream %d DEDStream %d", Stream, STREAM->DEDStream); - - if (Stream == 0) - STREAM->DEDStream = 31; // Pactor - - STREAM->Attached = TRUE; - - calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[Stream]->L4USER, STREAM->MyCall); - - STREAM->MyCall[calllen] = 0; - - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - - if (Stream == 0) - { - // Release Scan Lock if it is held - - TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit - - if (TNC->DontReleasePermission) - { - TNC->DontReleasePermission = FALSE; - TNC->DontWantToChangeFreq = TRUE; - } - - sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC"); - - Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet); - - SuspendOtherPorts(TNC); // Prevent connects on other ports in same scan gruop - - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - // Stop Scanner - - sprintf(Status, "%d SCANSTOP", TNC->Port); - TNC->SwitchToPactor = 0; // Cancel any RP to Pactor switch - - Rig_Command((TRANSPORTENTRY *) -1, Status); - } - else - { - sprintf(STREAM->CmdSet, "I%s\r", STREAM->MyCall); - Debugprintf("SCS Pactor Attach CMDSet = %s", STREAM->CmdSet); - } - } - } - - if (TNC->Timeout) - { - TNC->Timeout--; - - if (TNC->Timeout) // Still waiting - return; - - TNC->Retries--; - - if(TNC->Retries) - { - WriteCommBlock(TNC); // Retransmit Block - return; - } - - // Retried out. - - if (TNC->HostMode == 0) - { - DoTermModeTimeout(TNC); - return; - } - - // Retried out in host mode - Clear any connection and reinit the TNC - - Debugprintf("PACTOR - Link to TNC Lost"); - TNC->TNCOK = FALSE; - - sprintf(TNC->WEB_COMMSSTATE,"%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName); - SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - // Clear anything from UI_Q - - while (TNC->PortRecord->UI_Q) - { - UINT * buffptr = Q_REM(&TNC->PortRecord->UI_Q); - ReleaseBuffer(buffptr); - } - - - TNC->HostMode = 0; - TNC->ReinitState = 0; - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) // Connected - { - TNC->Streams[Stream].Connected = FALSE; // Back to Command Mode - TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node - } - } - } - - // We delay clearing busy for BusyHold secs - - if (TNC->Busy) - if (TNC->Mode != 7) - TNC->Busy--; - - if (TNC->BusyDelay) // Waiting to send connect - { - // Still Busy? - - if (InterlockedCheckBusy(TNC) == 0) - { - // No, so send - - TNC->Streams[0].CmdSet = TNC->ConnectCmd; - TNC->Streams[0].Connecting = TRUE; - TNC->Streams[0].ConnectTime = time(NULL); - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall); - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - Debugprintf("SCS Pactor CMDSet = %s", TNC->Streams[0].CmdSet); - - TNC->BusyDelay = 0; - return; - } - else - { - // Wait Longer - - TNC->BusyDelay--; - - if (TNC->BusyDelay == 0) - { - // Timed out - Send Error Response - - PMSGWITHLEN buffptr = GetBuff(); - - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = 39; - memcpy(buffptr->Data,"Sorry, Can't Connect - Channel is busy\r", 39); - - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - - free(TNC->ConnectCmd); - - } - } - } - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - STREAM = &TNC->Streams[Stream]; - - if (STREAM->Attached) - CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete); - - if (STREAM->NeedDisc) - { - STREAM->NeedDisc--; - - if (STREAM->NeedDisc == 0) - STREAM->ReportDISC = TRUE; - - } - - if (TNC->Timeout) - return; // We've sent something - } - - // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence - - if (!TNC->HostMode) - { - DoTNCReinit(TNC); - return; - } - - TNC->PollSent = FALSE; - - //If sending internal command list, send next element - - for (Stream = 0; Stream <= MaxStreams; Stream++) - { - if (TNC->Streams[Stream].CmdSet) - { - unsigned char * start, * end; - int len; - - start = TNC->Streams[Stream].CmdSet; - - if (*(start) == 250) // 2nd part of long KISS packet - { - len = start[1]; - - Poll[2] = 250; // KISS Channel - Poll[3] = 0; // Data - Poll[4] = len - 1; - memcpy(&Poll[5], &start[2], len); - - CRCStuffAndSend(TNC, Poll, len + 5); - - free(TNC->Streams[Stream].CmdSave); - TNC->Streams[Stream].CmdSet = NULL; - return; - } - - if (*(start) == 0) // End of Script - { - free(TNC->Streams[Stream].CmdSave); - TNC->Streams[Stream].CmdSet = NULL; - } - else - { - end = strchr(start, 13); - len = (int)(++end - start - 1); // exclude cr - TNC->Streams[Stream].CmdSet = end; - - if (*(start) == 1) - { - // This is UI data, not a command. Send it to channel 0 - - len --; - - Poll[2] = 0; // UI Channel - Poll[3] = 0; // Data - Poll[4] = len - 1; - memcpy(&Poll[5], &start[1], len); - - CRCStuffAndSend(TNC, Poll, len + 5); - - return; - } - - if (*(start) == 2) - { - // This is a UI command Send it to channel 0 - - len--; - - Poll[2] = 0; // UI Channel - Poll[3] = 1; // Command - Poll[4] = len - 1; - memcpy(&Poll[5], &start[1], len); - - CRCStuffAndSend(TNC, Poll, len + 5); - - return; - } - - Poll[2] = TNC->Streams[Stream].DEDStream; // Channel - Poll[3] = 1; // Command - Poll[4] = len - 1; - memcpy(&Poll[5], start, len); - - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], len); - CloseLogFile(TNC->Port); - - CRCStuffAndSend(TNC, Poll, len + 5); - - return; - } - } - } - // if Freq Change needed, check if ok to do it. - - if (TNC->TNCOK) - { - if (TNC->WantToChangeFreq) - { - Poll[2] = 31; // Command - Poll[3] = 1; // Command - Poll[4] = 2; // Len -1 - Poll[5] = '%'; - Poll[6] = 'W'; - Poll[7] = '0'; - - CRCStuffAndSend(TNC, Poll, 8); - - TNC->InternalCmd = TRUE; - TNC->WantToChangeFreq = FALSE; - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("Scan Debug SCS Pactor Requesting permission from TNC"); - - return; - } - - if (TNC->DontWantToChangeFreq) - { - Poll[2] = 31; // Command - Poll[3] = 1; // Command - Poll[4] = 2; // Len -1 - Poll[5] = '%'; - Poll[6] = 'W'; - Poll[7] = '1'; - - CRCStuffAndSend(TNC, Poll, 8); - - TNC->InternalCmd = TRUE; - TNC->DontWantToChangeFreq = FALSE; - TNC->OKToChangeFreq = FALSE; - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("Scan Debug SCS Pactor Release Scan Lock sent to TNC"); - - return; - } - } - - // Send Radio Command if avail - - if (TNC->TNCOK && TNC->BPQtoRadio_Q) - { - int datalen; - PMSGWITHLEN buffptr; - - buffptr = Q_REM(&TNC->BPQtoRadio_Q); - - datalen = (int)buffptr->Len; - - Poll[2] = 253; // Radio Channel - Poll[3] = 0; // Data? - Poll[4] = datalen - 1; - - memcpy(&Poll[5], buffptr->Data, datalen); - - ReleaseBuffer(buffptr); - - CRCStuffAndSend(TNC, Poll, datalen + 5); - - if (TNC->RIG->RIG_DEBUG) - { - Debugprintf("SCS Rig Command Queued, Len = %d", datalen ); - Debugprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - Poll[5], Poll[6], Poll[7], Poll[8], Poll[9], Poll[10], Poll[11], Poll[12], - Poll[13], Poll[14], Poll[15], Poll[16], Poll[17], Poll[18], Poll[19], Poll[20]); - } - - // Debugprintf("SCS Sending Rig Command"); - - return; - } - - if (TNC->TNCOK && TNC->PortRecord->UI_Q) - { - int datalen; - char * Buffer; - char ICall[16]; - char CCMD[80] = "C"; - char Call[12] = " "; - struct _MESSAGE * buffptr; - - buffptr = Q_REM(&TNC->PortRecord->UI_Q); - - datalen = buffptr->LENGTH - MSGHDDRLEN; - Buffer = &buffptr->DEST[0]; // Raw Frame - - Buffer[datalen] = 0; - - // If a Dragon with KISS over Hostmade we can just send it - - if (TNC->DragonKISS) - { - int EncLen; - - Poll[2] = 250; // KISS Channel - Poll[3] = 0; // CMD - Poll[4] = datalen + 2; // 3 extrac chars, but need Len - 1 - - Buffer--; - *(Buffer) = 0; // KISS Control on front - EncLen = KissEncode(Buffer, &Poll[5], datalen + 1); - - // We can only send 256 bytes in HostMode, so if longer will - // have to fragemt - - if (EncLen > 256) - { - //We have to wait for response before sending rest, so use CmdSet - - // We need to save the extra first, as CRC will overwrite the first two bytes - - UCHAR * ptr = TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(400); - - (*ptr++) = 250; // KISS Channel - (*ptr++) = EncLen - 256; - memcpy(ptr, &Poll[5 + 256], EncLen - 256); - - // Send first 256 - - Poll[4] = 255; //need Len - 1 - CRCStuffAndSend(TNC, Poll, 261); - } - else - { - Poll[4] = EncLen - 1; //need Len - 1 - CRCStuffAndSend(TNC, Poll, EncLen + 5); - } - - ReleaseBuffer((UINT *)buffptr); - return; - } - - // Not dragon KISS - - // Buffer has an ax.25 header, which we need to pick out and set as channel 0 Connect address - // before sending the beacon - - // We also need to set Chan 0 Mycall so digi'ing can work, and put - // it back after so incoming calls will work - - // But we cant set digipeated bit in call, so if we find one, skip message - - // This doesn't seem to work - - - ConvFromAX25(Buffer + 7, ICall); // Origin - strlop(ICall, ' '); - - ConvFromAX25(Buffer, &Call[1]); // Dest - strlop(&Call[1], ' '); - strcat(CCMD, Call); - Buffer += 14; // Skip Origin - datalen -= 7; - - while ((Buffer[-1] & 1) == 0) - { - if (Buffer[6] & 0x80) // Digied bit set? - { - ReleaseBuffer((UINT *)buffptr); - return; - } - - ConvFromAX25(Buffer, &Call[1]); - strlop(&Call[1], ' '); - strcat(CCMD, Call); - Buffer += 7; // End of addr - datalen -= 7; - } - - if (Buffer[0] == 3) // UI - { - Buffer += 2; - datalen -= 2; - - Poll[2] = 0; // UI Channel - Poll[3] = 1; // CMD - Poll[4] = (int)strlen(CCMD) - 1; - strcpy(&Poll[5], CCMD); - CRCStuffAndSend(TNC, Poll, Poll[4] + 6); // Set Dest and Path - - TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = zalloc(400); - sprintf(TNC->Streams[0].CmdSet, "%cI%s\r%c%s\r%cI%s\r", - 2, ICall, // Flag as Chan 0 Command - 1, Buffer, // Flag CmdSet as Data - 2, TNC->NodeCall); // Flag as Chan 0 Command - } - - ReleaseBuffer((UINT *)buffptr); - return; - } - - - // Check status Periodically - - if (TNC->TNCOK) - { - if (TNC->IntCmdDelay == 6) - { - Poll[2] = 254; // Channel - Poll[3] = 0x1; // Command - Poll[4] = 1; // Len-1 - Poll[5] = 'G'; // Extended Status Poll - Poll[6] = '3'; - - CRCStuffAndSend(TNC, Poll, 7); - - TNC->InternalCmd = TRUE; - TNC->IntCmdDelay--; - - return; - } - - if (TNC->IntCmdDelay == 4) - { - Poll[2] = 31; // Channel - Poll[3] = 0x1; // Command - Poll[4] = 1; // Len-1 - Poll[5] = '%'; // Bytes acked Status - Poll[6] = 'T'; - - CRCStuffAndSend(TNC, Poll, 7); - - TNC->InternalCmd = TRUE; - TNC->IntCmdDelay--; - - return; - } - - if (TNC->IntCmdDelay <=0) - { - Poll[2] = 31; // Channel - Poll[3] = 0x1; // Command - Poll[4] = 1; // Len-1 - Poll[5] = '@'; // Buffer Status - Poll[6] = 'B'; - - CRCStuffAndSend(TNC, Poll, 7); - - TNC->InternalCmd = TRUE; - TNC->IntCmdDelay = 20; // Every 2 secs - - return; - } - else - TNC->IntCmdDelay--; - } - - // If busy, send status poll, send Data if avail - - // We need to start where we last left off, or a busy stream will lock out the others - - for (nn = 0; nn <= MaxStreams; nn++) - { - Stream = TNC->LastStream++; - - if (TNC->LastStream > MaxStreams) - TNC->LastStream = 0; - - if (TNC->TNCOK && TNC->Streams[Stream].BPQtoPACTOR_Q) - { - int datalen; - PMSGWITHLEN buffptr; - char * Buffer; - - // Dont send to Pactor if waiting for Min Level to be reached - - if (TNC->MinLevelTimer && Stream == 0) - continue; - - buffptr = Q_REM(&TNC->Streams[Stream].BPQtoPACTOR_Q); - - datalen = (int)buffptr->Len; - Buffer = buffptr->Data; // Data portion of frame - - Poll[2] = TNC->Streams[Stream].DEDStream; // Channel - - if (TNC->Streams[Stream].Connected) - { - if (TNC->SwallowSignon && Stream == 0) - { - TNC->SwallowSignon = FALSE; - if (strstr(Buffer, "Connected")) // Discard *** connected - { - ReleaseBuffer(buffptr); - return; - } - } - - Poll[3] = 0; // Data? - TNC->Streams[Stream].BytesTXed += datalen; - - Poll[4] = datalen - 1; - memcpy(&Poll[5], Buffer, datalen); - - WritetoTrace(TNC, Buffer, datalen); - - ReleaseBuffer(buffptr); - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], datalen); - CloseLogFile(TNC->Port); - - CRCStuffAndSend(TNC, Poll, datalen + 5); - - TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected; - - if (STREAM->Disconnecting && TNC->Streams[Stream].BPQtoPACTOR_Q == 0) - TidyClose(TNC, 0); - - return; - } - - // Command. Do some sanity checking and look for things to process locally - - Poll[3] = 1; // Command - datalen--; // Exclude CR - Buffer[datalen] = 0; // Null Terminate - _strupr(Buffer); - - if (_memicmp(Buffer, "DD", 2) == 0) - { - // Send DD (Dirty Disconnect) - - // Uses "Hidden" feature where you can send any normal mode command - // in host mode by preceeding with a # - - Poll[2] = 31; - Poll[3] = 0x1; - Poll[4] = 2; - sprintf(&Poll[5], "#DD\r"); - CRCStuffAndSend(TNC, Poll, 8); - - // It looks like there isn't a response - - TNC->Timeout = 0; - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], 4); - CloseLogFile(TNC->Port); - - ReleaseBuffer(buffptr); - return; - } - - if (_memicmp(Buffer, "D", 1) == 0) - { - TNC->Streams[Stream].ReportDISC = TRUE; // Tell Node - ReleaseBuffer(buffptr); - return; - } - - if (memcmp(Buffer, "RADIO ", 6) == 0) - { - sprintf(&Buffer[40], "%d %s", TNC->Port, &Buffer[6]); - - if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &Buffer[40])) - { - ReleaseBuffer(buffptr); - } - else - { - buffptr->Len = sprintf(buffptr->Data, "%s", &Buffer[40]); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - } - return; - } - - if (_memicmp(Buffer, "SessionTimeLimit", 16) == 0) - { - if (Buffer[16] != 13) - { - PMSGWITHLEN buffptr = (PMSGWITHLEN)GetBuff(); - - TNC->SessionTimeLimit = atoi(&Buffer[16]) * 60; - - if (buffptr) - { - buffptr->Len = sprintf((UCHAR *)&buffptr->Data[0], "SCS} OK\r"); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - } - return; - } - } - - if (memcmp(Buffer, "MYLEVEL ", 8) == 0) - { - Switchmode(TNC, Buffer[8] - '0'); - TNC->Bandwidth = Buffer[8]; // so scanner knows where we are - - buffptr->Len = sprintf(buffptr->Data, "Ok\r"); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return; - } - - if (memcmp(Buffer, "CHECKLEVEL", 10) == 0) - { - CheckMode(TNC); - - buffptr->Len = sprintf(buffptr->Data, "%s\r", &TNC->RXBuffer[2]); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return; - } - - if (_memicmp(Buffer, "OVERRIDEBUSY", 12) == 0) - { - TNC->OverrideBusy = TRUE; - - buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r"); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return; - } - - if ((Stream == 0) && memcmp(Buffer, "RPACKET", 7) == 0) - { - TNC->HFPacket = TRUE; - buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r"); - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - return; - } - - if ((Stream == 0) && memcmp(Buffer, "PACTOR", 6) == 0) - { - TNC->HFPacket = FALSE; - buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r"); - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - return; - } - - - if ((Stream == 0) && memcmp(Buffer, "EXITHOST", 8) == 0) - { - UCHAR * Poll = TNC->TXBuffer; - - TNC->UsingTermMode = 1; - - ExitHost(TNC); - - // Send CR to get prompt from TNC - - Poll[0] = 13; - TNC->TXLen = 1; - WriteCommBlock(TNC); - - ReleaseBuffer(buffptr); - return; - } - if (Stream == 0 && Buffer[0] == 'C' && datalen > 2) // Pactor Connect - Poll[2] = TNC->Streams[0].DEDStream = 31; // Pactor Channel - - if (Stream == 0 && Buffer[0] == 'R' && Buffer[1] == 'C') // Robust Packet Connect - { - Poll[2] = TNC->Streams[0].DEDStream = 30; // Last Packet Channel - memmove(Buffer, &Buffer[1], datalen--); - } - - if (Buffer[0] == 'C' && datalen > 2) // Connect - { - if (*(++Buffer) == ' ') Buffer++; // Space isn't needed - - if ((memcmp(Buffer, "P1 ", 3) == 0) ||(memcmp(Buffer, "P2 ", 3) == 0)) - { - // Port Selector for Packet Connect convert to 2:CALL - - Buffer[0] = Buffer[1]; - Buffer[1] = ':'; - memmove(&Buffer[2], &Buffer[3], datalen--); - //Buffer += 2; - } - - memcpy(TNC->Streams[Stream].RemoteCall, Buffer, 9); - - TNC->Streams[Stream].Connecting = TRUE; - - if (Stream == 0) - { - // Send Call, Mode Command followed by connect - - TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100); - - if (TNC->Dragon) - sprintf(TNC->Streams[0].CmdSet, "I%s\r%s\r", TNC->Streams[0].MyCall, buffptr->Data); - else - { - if (TNC->Streams[0].DEDStream == 31) - sprintf(TNC->Streams[0].CmdSet, "I%s\rPT\r%s\r", TNC->Streams[0].MyCall, buffptr->Data); - else - sprintf(TNC->Streams[0].CmdSet, "I%s\rPR\r%s\r", TNC->Streams[0].MyCall, buffptr->Data); - } - - ReleaseBuffer(buffptr); - - // See if Busy - - if (InterlockedCheckBusy(TNC)) - { - // Channel Busy. Unless override set, wait - - if (TNC->OverrideBusy == 0) - { - // Send Mode Command now, save command, and wait up to 10 secs - // No, leave in Pactor, or Busy Detect won't work. Queue the whole conect sequence - - TNC->ConnectCmd = TNC->Streams[0].CmdSet; - TNC->Streams[0].CmdSet = NULL; - - sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel"); - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - TNC->BusyDelay = TNC->BusyWait * 10; - TNC->Streams[Stream].Connecting = FALSE; // Not connecting Yet - - return; - } - } - - TNC->OverrideBusy = FALSE; - - sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[Stream].MyCall, TNC->Streams[Stream].RemoteCall); - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - Debugprintf("SCS Pactor CMDSet = %s", TNC->Streams[Stream].CmdSet); - - TNC->Streams[0].InternalCmd = FALSE; - return; - } - } - - - Poll[4] = datalen - 1; - memcpy(&Poll[5], buffptr->Data, datalen); - - // if it starts with # the tnc won't respond, so send OK now. - - if (Buffer[0] == '#') - { - TNC->HFPacket = TRUE; - buffptr->Len = sprintf(buffptr->Data, "SCS} OK\r"); - C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr); - } - else - ReleaseBuffer(buffptr); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], datalen); - CloseLogFile(TNC->Port); - - CRCStuffAndSend(TNC, Poll, datalen + 5); - - TNC->Streams[Stream].InternalCmd = TNC->Streams[Stream].Connected; - - return; - } - - // if frames outstanding, issue a poll - - if (TNC->Streams[Stream].FramesOutstanding) - { - Poll[2] = TNC->Streams[Stream].DEDStream; - Poll[3] = 0x1; // Command - Poll[4] = 0; // Len-1 - Poll[5] = 'L'; // Status - - CRCStuffAndSend(TNC, Poll, 6); - - TNC->InternalCmd = TRUE; - TNC->IntCmdDelay--; - return; - } - - } - - TNC->PollSent = TRUE; - - // Use General Poll (255) - - Poll[2] = 255 ; // Channel - Poll[3] = 0x1; // Command - - if (TNC->ReinitState == 3) - { - TNC->ReinitState = 0; - Poll[3] = 0x41; - } - - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - - CRCStuffAndSend(TNC, Poll, 6); - TNC->InternalCmd = FALSE; - - return; - -} - -void SCSTryToSendDATA(struct TNCINFO * TNC, int Stream) -{ - // Used after queuing data to see if it can be sent immediately - - struct STREAMINFO * STREAM = &TNC->Streams[Stream]; - int datalen; - PMSGWITHLEN buffptr; - char * Buffer; - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->TNCOK == 0 || STREAM->BPQtoPACTOR_Q == 0 || STREAM->Connected == 0) - return; - - - // Dont send to Pactor if waiting for Min Level to be reached - - if (TNC->MinLevelTimer && Stream == 0) - return;; - - Sleep(10); // Give TNC time to respond - - SCSCheckRX(TNC); // See if anything received - - if (TNC->Timeout) - return; // Link busy - - buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q); - - datalen = (int)buffptr->Len; - Buffer = buffptr->Data; // Data portion of frame - - Poll[2] = STREAM->DEDStream; // Channel - - if (TNC->SwallowSignon && Stream == 0) - { - TNC->SwallowSignon = FALSE; - - if (strstr(Buffer, "Connected")) // Discard *** connected - { - ReleaseBuffer(buffptr); - return; - } - } - - Poll[3] = 0; // Data - STREAM->BytesTXed += datalen; - - Poll[4] = datalen - 1; - memcpy(&Poll[5], Buffer, datalen); - - WritetoTrace(TNC, Buffer, datalen); - - ReleaseBuffer(buffptr); - OpenLogFile(TNC->Port); - - WriteLogLine(TNC->Port, &Poll[5], datalen); - CloseLogFile(TNC->Port); - - CRCStuffAndSend(TNC, Poll, datalen + 5); - - if (STREAM->Disconnecting && STREAM->BPQtoPACTOR_Q == 0) - TidyClose(TNC, Stream); - - return; -} - - -VOID DoTNCReinit(struct TNCINFO * TNC) -{ - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->ReinitState == 0) - { - // Just Starting - Send a TNC Mode Command to see if in Terminal or Host Mode - - TNC->TNCOK = FALSE; - sprintf(TNC->WEB_COMMSSTATE,"%s Initialising TNC", TNC->PortRecord->PORTCONTROL.SerialPortName); - SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - Poll[0] = 13; - Poll[1] = 0x1B; - TNC->TXLen = 2; - - if (WriteCommBlock(TNC) == FALSE) - { - CloseCOMPort(TNC->hDevice); - OpenCOMMPort(TNC, TNC->PortRecord->PORTCONTROL.SerialPortName, TNC->PortRecord->PORTCONTROL.BAUDRATE, TRUE); - } - - TNC->Retries = 1; - } - - if (TNC->ReinitState == 1) // Forcing back to Term - TNC->ReinitState = 0; - - if (TNC->ReinitState == 2) // In Term State, Sending Initialisation Commands - { - char * start, * end; - int len; - - start = TNC->InitPtr; - - if (*(start) == 0) // End of Script - { - // Put into Host Mode - - Debugprintf("DOTNCReinit Complete - Entering Hostmode"); - - TNC->TXBuffer[2] = 0; - TNC->Toggle = 0; - - memcpy(Poll, "JHOST4\r", 7); - - TNC->TXLen = 7; - WriteCommBlock(TNC); - - // Timeout will enter host mode - - TNC->Timeout = 1; - TNC->Retries = 1; - TNC->Toggle = 0; - TNC->ReinitState = 3; // Set toggle force bit - TNC->OKToChangeFreq = 1; // In case failed whilst waiting for permission - - return; - } - - end = strchr(start, 13); - len = (int)(++end - start); - TNC->InitPtr = end; - memcpy(Poll, start, len); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, Poll, len); - CloseLogFile(TNC->Port); - - TNC->TXLen = len; - WriteCommBlock(TNC); - - TNC->Retries = 2; - } -} - -static VOID DoTermModeTimeout(struct TNCINFO * TNC) -{ - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->ReinitState == 0) - { - //Checking if in Terminal Mode - Try to set back to Term Mode - - TNC->ReinitState = 1; - ExitHost(TNC); - TNC->Retries = 1; - - return; - } - - if (TNC->ReinitState == 1) - { - // Forcing back to Term Mode - - TNC->ReinitState = 0; - DoTNCReinit(TNC); // See if worked - return; - } - - if (TNC->ReinitState == 3) - { - // Entering Host Mode - - // Assume ok - - TNC->HostMode = TRUE; - TNC->IntCmdDelay = 10; - - return; - } -} - -BOOL CheckRXText(struct TNCINFO * TNC) -{ - int Length; - - // only try to read number of bytes in queue - - if (TNC->RXLen == 500) - TNC->RXLen = 0; - - Length = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen); - - if (Length == 0) - return FALSE; // Nothing doing - - TNC->RXLen += Length; - - Length = TNC->RXLen; - - TNC->RXBuffer[TNC->RXLen] = 0; - - if (strlen(TNC->RXBuffer) < TNC->RXLen) - TNC->RXLen = 0; - - if ((strstr(TNC->RXBuffer, "cmd: ") == 0) && (strstr(TNC->RXBuffer, "pac: ") == 0)) - return 0; // Wait for rest of frame - - // Complete Char Mode Frame - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, TNC->RXBuffer, TNC->RXLen); - CloseLogFile(TNC->Port); - - TNC->RXBuffer[TNC->RXLen] = 0; - - if (TNC->RIG->RIG_DEBUG) - Debugprintf(TNC->RXBuffer); - - TNC->RXLen = 0; // Ready for next frame - - return TRUE; -} - -BOOL CheckRXHost(struct TNCINFO * TNC, char * UnstuffBuffer) -{ - int Length; - unsigned short crc; - - // only try to read number of bytes in queue - - if (TNC->RXLen == 500) - TNC->RXLen = 0; - - Length = ReadCOMBlock(TNC->hDevice, &TNC->RXBuffer[TNC->RXLen], 500 - TNC->RXLen); - - if (Length == 0) - return FALSE; // Nothing doing - - TNC->RXLen += Length; - - Length = TNC->RXLen; - - if (Length < 6) // Minimum Frame Sise - return FALSE; - - if (TNC->RXBuffer[2] == 170) - { - // Retransmit Request - - TNC->RXLen = 0; - return FALSE; // Ignore for now - } - - // Can't unstuff into same buffer - fails if partial msg received, and we unstuff twice - - Length = Unstuff(&TNC->RXBuffer[2], &UnstuffBuffer[2], Length - 2); - - if (Length == -1) - { - // Unstuff returned an errors (170 not followed by 0) - - TNC->RXLen = 0; - return FALSE; // Ignore for now - } - - crc = compute_crc(&UnstuffBuffer[2], Length); - - if (crc == 0xf0b8) // Good CRC - { - TNC->RXLen = 0; // Ready for next frame - return TRUE; - } - - // Bad CRC - assume incomplete frame, and wait for rest. If it was a full bad frame, timeout and retry will recover link. - - return FALSE; -} - - -//#include "Mmsystem.h" - -int Sleeptime = 250; - -int CheckMode(struct TNCINFO * TNC) -{ - int n; - char UnstuffBuffer[500]; - - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->HostMode == 0) - return 0; // Don't try if initialising - - TNC->EnterExit = TRUE; - - Poll[2] = 31; - Poll[3] = 0x41; - Poll[4] = 0x5; - memcpy(&Poll[5], "JHOST0", 6); - - CRCStuffAndSend(TNC, Poll, 11); - - n = 0; - - while (CheckRXHost(TNC, UnstuffBuffer) == FALSE) - { - Sleep(5); - n++; - - if (n > 100) break; - } - - - sprintf(Poll, "MYL\r"); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, Poll, 3); - CloseLogFile(TNC->Port); - - TNC->TXLen = 4; - WriteCommBlock(TNC); - - n = 0; - - while (CheckRXText(TNC) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - - memcpy(Poll, "JHOST4\r", 7); - - TNC->TXLen = 7; - WriteCommBlock(TNC); - - // No response expected - - Sleep(10); - - Poll[2] = 255; // Channel - TNC->Toggle = 0; - Poll[3] = 0x41; - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - - CRCStuffAndSend(TNC, Poll, 6); - TNC->InternalCmd = FALSE; - TNC->Timeout = 5; // 1/2 sec - In case missed - - TNC->EnterExit = FALSE; - return 0; -} - - -int Switchmode(struct TNCINFO * TNC, int Mode) -{ - int n; - char UnstuffBuffer[500]; - - UCHAR * Poll = TNC->TXBuffer; - - if (TNC->HostMode == 0) - return 0; // Don't try if initialising - - if (TNC->HFPacket) - { - Poll[2] = 31; - Poll[3] = 0x1; - Poll[4] = 0x1; - memcpy(&Poll[5], "PT", 2); - CRCStuffAndSend(TNC, Poll, 7); - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, "SwitchModes - Setting Pactor", 28); - CloseLogFile(TNC->Port); - - TNC->HFPacket = FALSE; - TNC->Streams[0].DEDStream = 31; // Pactor Channel - - n = 0; - while (CheckRXHost(TNC, UnstuffBuffer) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - -// Debugprintf("Set Pactor ACK received in %d mS, Sleeping for %d", 5 * n, Sleeptime); - Sleep(Sleeptime); - } - - // Uses "Hidden" feature where you can send any normal mode command - // in host mode by preceeding with a # - - Poll[2] = 31; - Poll[3] = 0x1; - Poll[4] = 5; - sprintf(&Poll[5], "#MYL %d\r", Mode); - CRCStuffAndSend(TNC, Poll, 11); - - // It looks like there isn't a response - - TNC->Timeout = 0; - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], 6); - CloseLogFile(TNC->Port); - - return 0; -} - -VOID SwitchToPactor(struct TNCINFO * TNC) -{ - if (TNC->ForceRobust) - return; - - TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100); - sprintf(TNC->Streams[0].CmdSet, "PT\r"); - - TNC->HFPacket = FALSE; - TNC->Streams[0].DEDStream = 31; // Pactor Channel - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("BPQ32 Scan - switch to Pactor"); -} - -VOID SwitchToPacket(struct TNCINFO * TNC) -{ - TNC->Streams[0].CmdSet = TNC->Streams[0].CmdSave = malloc(100); - sprintf(TNC->Streams[0].CmdSet, "PR\r"); - - TNC->HFPacket = TRUE; - TNC->Streams[0].DEDStream = 30; // Packet Channel - - TNC->SwitchToPactor = TNC->RobustTime; - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("BPQ32 Scan - switch to Packet"); -} - -VOID ExitHost(struct TNCINFO * TNC) -{ - UCHAR * Poll = TNC->TXBuffer; - - // Try to exit Host Mode - - TNC->TXBuffer[2] = 31; - TNC->TXBuffer[3] = 0x41; - TNC->TXBuffer[4] = 0x5; - memcpy(&TNC->TXBuffer[5], "JHOST0", 6); - - CRCStuffAndSend(TNC, Poll, 11); - return; -} - -VOID CRCStuffAndSend(struct TNCINFO * TNC, UCHAR * Msg, int Len) -{ - unsigned short int crc; - UCHAR StuffedMsg[500]; - int i, j; - - Msg[3] |= TNC->Toggle; - TNC->Toggle ^= 0x80; - - crc = compute_crc(&Msg[2], Len-2); - crc ^= 0xffff; - - Msg[Len++] = (crc&0xff); - Msg[Len++] = (crc>>8); - - for (i = j = 2; i < Len; i++) - { - StuffedMsg[j++] = Msg[i]; - if (Msg[i] == 170) - { - StuffedMsg[j++] = 0; - } - } - - if (j != i) - { - Len = j; - memcpy(Msg, StuffedMsg, j); - } - - TNC->TXLen = Len; - - Msg[0] = 170; - Msg[1] = 170; - - WriteCommBlock(TNC); - - TNC->Retries = 5; -} - -int Unstuff(UCHAR * MsgIn, UCHAR * MsgOut, int len) -{ - int i, j=0; - - for (i=0; iTXBuffer; - - if (TNC->ReinitState == 0) - { - // Testing if in Term Mode. It is, so can now send Init Commands - - TNC->InitPtr = TNC->InitScript; - TNC->ReinitState = 2; - - // Send Restart to make sure PTC is in a known state - - strcpy(Poll, "RESTART\r"); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, Poll, 7); - CloseLogFile(TNC->Port); - - TNC->TXLen = 8; - WriteCommBlock(TNC); - - TNC->Timeout = 60; // 6 secs - - return; - } - if (TNC->ReinitState == 2) - { - // Sending Init Commands - - if (strstr(TNC->RXBuffer, "SCS P4dragon")) - { - TNC->Dragon = TRUE; - Debugprintf("SCSPactor in P4dragon mode"); - } - - DoTNCReinit(TNC); // Send Next Command - return; - } -} - -VOID ProcessIncomingCall(struct TNCINFO * TNC, struct STREAMINFO * STREAM, int Stream) -{ - APPLCALLS * APPL; - char * ApplPtr = APPLS; - int App; - char Appl[10]; - char FreqAppl[10] = ""; // Frequecy-specific application - char DestCall[10]; - TRANSPORTENTRY * SESS; - struct WL2KInfo * WL2K = TNC->WL2K; - UCHAR * ptr; - UCHAR Buffer[80]; - PMSGWITHLEN buffptr; - BOOL PactorCall = FALSE; - - char * Call = STREAM->RemoteCall; - - if (Stream > 0 && Stream < 30) - ProcessIncommingConnectEx(TNC, Call, Stream, FALSE, TRUE); // No CTEXT - else - ProcessIncommingConnectEx(TNC, Call, Stream, TRUE, TRUE); - - SESS = TNC->PortRecord->ATTACHEDSESSIONS[Stream]; - - if (SESS == NULL) - return; // Cant do much without one - - if (Stream > 0 && Stream < 30) - { - // Packet Connect. Much safer to process here, even though it means - // duplicating some code, or the Pactor/RP mode tests get very complicated - - int Len = 0; - struct PORTCONTROL * PORT = &TNC->PortRecord->PORTCONTROL; - - strcpy(DestCall, STREAM->MyCall); - Debugprintf("PTC Packet Incoming Call - MYCALL = *%s*", DestCall); - - for (App = 0; App < 32; App++) - { - APPL=&APPLCALLTABLE[App]; - memcpy(Appl, APPL->APPLCALL_TEXT, 10); - - ptr=strchr(Appl, ' '); - - if (ptr) - *ptr = 0; - - if (_stricmp(DestCall, Appl) == 0) - break; - } - - if (App < 32) - { - char AppName[13]; - - memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12); - AppName[12] = 0; - - // Make sure app is available - - Debugprintf("Connect is to APPL %s", AppName); - - if (CheckAppl(TNC, AppName)) - { - int MsgLen = sprintf(Buffer, "%s\r", AppName); - - buffptr = GetBuff(); - - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = MsgLen; - - memcpy(buffptr->Data, Buffer, MsgLen); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - } - else - { - char Msg[] = "Application not available\r\n"; - - // Send a Message, then a disconenct - - buffptr = GetBuff(); - - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = (int)strlen(Msg); - memcpy(buffptr->Data, Msg, strlen(Msg)); - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - STREAM->NeedDisc = 100; // 10 secs - } - return; - } - - // Not to a known appl - drop through to Node - - if (PORT->CTEXT) - { - Len = strlen(PORT->CTEXT); - ptr = PORT->CTEXT; - } - else if (CTEXTLEN) - { - Len = CTEXTLEN; - ptr = CTEXTMSG; - } - else - return; - - while (Len > 0) - { - int sendLen = TNC->PortRecord->ATTACHEDSESSIONS[Stream]->SESSPACLEN; - - if (sendLen == 0) - sendLen = 80; - - if (Len < sendLen) - sendLen = Len; - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = sendLen; - memcpy(buffptr->Data, ptr, sendLen); - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - ptr += sendLen; - Len -= sendLen; - } - return; - } - - //Connect on HF port. May be Pactor or RP on some models - - if (STREAM->DEDStream == 31) - PactorCall = TRUE; - - if (TNC->RIG && TNC->RIG != &TNC->DummyRig) - { - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound Freq %s", STREAM->RemoteCall, TNC->NodeCall, TNC->RIG->Valchar); - SESS->Frequency = (int)(atof(TNC->RIG->Valchar) * 1000000.0) + 1500; // Convert to Centre Freq - - // If Scan Entry has a Appl, save it - - if (PactorCall && TNC->RIG->FreqPtr && TNC->RIG->FreqPtr[0]->APPL[0]) - strcpy(FreqAppl, &TNC->RIG->FreqPtr[0]->APPL[0]); - } - else - { - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Inbound", STREAM->RemoteCall, TNC->NodeCall); - if (WL2K) - SESS->Frequency = WL2K->Freq; - } - - if (WL2K) - strcpy(SESS->RMSCall, WL2K->RMSCall); - - SESS->Mode = PleveltoMode[TNC->Streams[Stream].PTCStatus1]; - - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - if (PactorCall && TNC->MinLevel > 1) - TNC->MinLevelTimer = 150; // Check we have reached right level - - // See which application the connect is for - - strcpy(DestCall, STREAM->MyCall); - - if (PactorCall) - Debugprintf("Pactor Incoming Call - MYCALL = *%s*", DestCall); - else - Debugprintf("HF Packet/RP Incoming Call - MYCALL = *%s*", DestCall); - - if ((PactorCall && TNC->UseAPPLCallsforPactor) || (PactorCall == 0 && TNC->UseAPPLCalls)) - // Test for Richard - Should drop through to Node if not to an APPLCALL - //&& strcmp(DestCall, TNC->NodeCall) != 0) // Not Connect to Node Call - { - for (App = 0; App < 32; App++) - { - APPL=&APPLCALLTABLE[App]; - memcpy(Appl, APPL->APPLCALL_TEXT, 10); - ptr=strchr(Appl, ' '); - - if (ptr) - *ptr = 0; - - if (_stricmp(DestCall, Appl) == 0) - break; - } - - if (App < 32) - { - char AppName[13]; - - memcpy(AppName, &ApplPtr[App * sizeof(CMDX)], 12); - AppName[12] = 0; - - // if SendTandRtoRelay set and Appl is RMS change to RELAY - - if (TNC->SendTandRtoRelay && memcmp(AppName, "RMS ", 4) == 0 - && (strstr(Call, "-T" ) || strstr(Call, "-R"))) - strcpy(AppName, "RELAY "); - - // Make sure app is available - - Debugprintf("Connect is to APPL %s", AppName); - - if (CheckAppl(TNC, AppName)) - { - int MsgLen = sprintf(Buffer, "%s\r", AppName); - buffptr = GetBuff(); - - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = MsgLen; - memcpy(buffptr->Data, Buffer, MsgLen); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - } - else - { - char Msg[] = "Application not available\r\n"; - - // Send a Message, then a disconenct - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = strlen(Msg); - memcpy(buffptr->Data, Msg, strlen(Msg)); - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - STREAM->NeedDisc = 100; // 10 secs - } - return; - } - - // Not to a known appl - drop through to Node - } - - if (!PactorCall && TNC->UseAPPLCalls) - goto DontUseAPPLCmd; // Don't use APPL= for Packet Calls - - // if SendTandRtoRelay set and Appl is RMS change to RELAY - - if (TNC->SendTandRtoRelay && strcmp(FreqAppl, "RMS") == 0 - && (strstr(Call, "-T" ) || strstr(Call, "-R"))) - strcpy(FreqAppl, "RELAY"); - - Debugprintf("Pactor Call is %s Freq Specific Appl is %s Freq is %s", - DestCall, FreqAppl, TNC->RIG->Valchar); - - if (FreqAppl[0]) // Frequency specific APPL overrides TNC APPL - { - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - Debugprintf("Using Freq Specific Appl %s", FreqAppl); - - buffptr->Len = sprintf(buffptr->Data, "%s\r", FreqAppl); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - return; - } - - // If an autoconnect APPL is defined, send it - - if (TNC->ApplCmd) - { - char App[16]; - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - strcpy(App, TNC->ApplCmd); - - Debugprintf("Using Default Appl *%s*, connecting call is %s", App, Call); - - // if SendTandRtoRelay set and Appl is RMS change to RELAY - - if (TNC->SendTandRtoRelay && memcmp(App, "RMS", 3) == 0 - && (strstr(Call, "-T" ) || strstr(Call, "-R"))) - { - strcpy(App, "RELAY"); - Debugprintf("Radio Only Call - Connecting to RELAY"); - } - - buffptr->Len = sprintf(buffptr->Data, "%s\r", App); - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - TNC->SwallowSignon = TRUE; - return; - } - -DontUseAPPLCmd: - - if (FULL_CTEXT && CTEXTLEN && HFCTEXTLEN == 0) - { - int Len = CTEXTLEN, CTPaclen = 100; - int Next = 0; - - while (Len > CTPaclen) // CTEXT Paclen - { - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = CTPaclen; - memcpy(buffptr->Data, &CTEXTMSG[Next], CTPaclen); - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - - Next += CTPaclen; - Len -= CTPaclen; - } - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = Len; - memcpy(buffptr->Data, &CTEXTMSG[Next], Len); - C_Q_ADD(&STREAM->BPQtoPACTOR_Q, buffptr); - } -} - -VOID ProcessDEDFrame(struct TNCINFO * TNC, UCHAR * Msg, int framelen) -{ - PMSGWITHLEN buffptr; - UCHAR * Buffer; // Data portion of frame - char Status[80]; - unsigned int Stream = 0, RealStream; - - if (TNC->HostMode == 0) - return; - - // Any valid frame is an ACK - - TNC->Timeout = 0; - - if (TNC->TNCOK == FALSE) - { - // Just come up - - struct RIGPORTINFO * PORT; - - TNC->TNCOK = TRUE; - sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName); - SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE); - - // If using an FT847 on PTC Port it needa a "Cat On" Command. Send it here - - if (TNC->RIG->PORT && TNC->RIG->PORT->PTC) - { - PORT = TNC->RIG->PORT; - - if (strcmp(PORT->Rigs[0].RigName, "FT847") == 0) - { - UCHAR CATON[6] = {0,0,0,0,0}; - SendPTCRadioCommand(PORT->PTC, CATON, 5); - } - } - } - - Stream = RealStream = Msg[2]; - - if (Stream > 29) - Stream = 0; // 31 = Pactor or 30 = Robust Packet Outgoing - - // if in Dragon Single Mode (Pactor and Packet on Same Port) - // we only use stream 0, so if a packet frame, set DEDStream - - // Im not convinced this is the bast place to do this, but let's try - - if (TNC->DragonSingle && RealStream && RealStream < 31) // Not a Pactor or control frame - { - // must be packet - - TNC->Streams[0].DEDStream = RealStream; // Packet Channel - Stream = 0; - } - - if (TNC->TXBuffer[5] == '#') // Shouldnt happen! - return; - - - // See if Poll Reply or Data - - if (Msg[3] == 0) - { - // Success - Nothing Follows - - if (Stream < 32) - if (TNC->Streams[Stream].CmdSet) - return; // Response to Command Set - - if ((TNC->TXBuffer[3] & 1) == 0) // Data - return; - - // If the response to a Command, then we should convert to a text "Ok" for forward scripts, etc - - if (TNC->TXBuffer[5] == 'G') // Poll - return; - - if (TNC->TXBuffer[5] == 'C') // Connect - reply we need is async - return; - - if (TNC->TXBuffer[5] == 'L') // Shouldnt happen! - return; - - if (TNC->TXBuffer[5] == '#') // Shouldnt happen! - return; - - if (TNC->TXBuffer[5] == '%' && TNC->TXBuffer[6] == 'W') // Scan Control - Response to W1 - if (TNC->InternalCmd) - return; // Just Ignore - - if (TNC->TXBuffer[5] == 'J') // JHOST - { - if (TNC->TXBuffer[10] == '0') // JHOST0 - { - TNC->Timeout = 1; // - return; - } - } - - if (TNC->Streams[Stream].Connected) - return; - - buffptr = GetBuff(); - - if (buffptr == NULL) return; // No buffers, so ignore - - buffptr->Len = sprintf(buffptr->Data,"Pactor} Ok\r"); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, buffptr->Data, (int)buffptr->Len); - CloseLogFile(TNC->Port); - - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - return; - } - - if (Msg[3] > 0 && Msg[3] < 6) - { - // Success with message - null terminated - - UCHAR * ptr; - int len; - - if (Msg[2] == 0xff) // General Poll Response - { - UCHAR * Poll = TNC->TXBuffer; - UCHAR Chan = Msg[4] - 1; - - if (Chan == 255) // Nothing doing - return; - - if (Msg[5] != 0) - { - // More than one to poll - save the list of channels to poll - - strcpy(TNC->NexttoPoll, &Msg[5]); - } - - // Poll the channel that had data - - Poll[2] = Chan; // Channel - Poll[3] = 0x1; // Command - - if (Chan == 254) // Status - Send Extended Status (G3) - { - Poll[4] = 1; // Len-1 - Poll[5] = 'G'; // Extended Status Poll - Poll[6] = '3'; - } - else - { - Poll[4] = 0; // Len-1 - Poll[5] = 'G'; // Poll - } - - CRCStuffAndSend(TNC, Poll, Poll[4] + 6); - TNC->InternalCmd = FALSE; - - return; - } - - Buffer = &Msg[4]; - - ptr = strchr(Buffer, 0); - - if (ptr == 0) - return; - - *(ptr++) = 13; - *(ptr) = 0; - - len = (int)(ptr - Buffer); - - if (len > 256) - return; - - // See if we need to process locally (Response to our command, Incoming Call, Disconencted, etc - - if (Msg[3] < 3) // 1 or 2 - Success or Fail - { - char LastCmd = TNC->TXBuffer[5]; - struct STREAMINFO * STREAM = &TNC->Streams[Stream]; - - // See if a response to internal command - - if (TNC->RIG->RIG_DEBUG) - if (LastCmd == 'I') - Debugprintf("SCS I Cmd Response %s", Buffer); - - if (LastCmd == 'I' && STREAM->CheckingCall == TRUE) - { - // We've received a connect and are checking MYCALL - - Debugprintf("SCS Incoming Call I Cmd Response %s Stream %d DED Stream %d", Buffer, Stream, RealStream); - - strlop(Buffer, 13); - strcpy(STREAM->MyCall, Buffer); - - ProcessIncomingCall(TNC, STREAM, Stream); - STREAM->CheckingCall = FALSE; - return; - } - - if (TNC->InternalCmd) - { - // Process it - - if (LastCmd == 'L') // Status - { - int s1, s2, s3, s4, s5, s6, num; - - num = sscanf(Buffer, "%d %d %d %d %d %d", &s1, &s2, &s3, &s4, &s5, &s6); - - TNC->Streams[Stream].FramesOutstanding = s3; - - // flow control debug - - sprintf(TNC->WEB_BUFFERS, "%d Q %d", TNC->Buffers, TNC->Streams[0].FramesOutstanding); - SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS); - - return; - } - - if (LastCmd == '@') // @ Commands - { - if (TNC->TXBuffer[6]== 'B') // Buffer Status - { - TNC->Buffers = atoi(Buffer); - sprintf(TNC->WEB_BUFFERS, "%d Q %d", TNC->Buffers, TNC->Streams[0].FramesOutstanding); - SetWindowText(TNC->xIDC_BUFFERS, TNC->WEB_BUFFERS); - return; - } - } - - if (LastCmd == '%') // % Commands - { - if (TNC->TXBuffer[6]== 'T') // TX count Status - { - sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %s", TNC->Streams[Stream].BytesRXed, TNC->Streams[Stream].BytesTXed, Buffer); - SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC); - return; - } - - if (TNC->TXBuffer[6] == 'W') // Scan Control - { - if (Msg[4] == '1') // Ok to Change - { - TNC->OKToChangeFreq = 1; - TNC->TimeScanLocked = 0; - if (TNC->RIG->RIG_DEBUG) - Debugprintf("Scan Debug SCS Pactor TNC gave permission"); - } - else - { - TNC->OKToChangeFreq = -1; - if (TNC->SyncSupported == FALSE && TNC->UseAPPLCallsforPactor && TNC->TimeScanLocked == 0) - TNC->TimeScanLocked = time(NULL); - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("Scan Debug SCS Pactor TNC refused permission"); - - } - } - } - return; - } - } - - if (Msg[3] == 3) // Status - { - struct STREAMINFO * STREAM = &TNC->Streams[Stream]; - - if (strstr(Buffer, "DISCONNECTED") || strstr(Buffer, "LINK FAILURE")) - { - if ((STREAM->Connecting | STREAM->Connected) == 0) - return; - - if (STREAM->Connecting && STREAM->Disconnecting == FALSE) - { - // Connect Failed - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = sprintf(buffptr->Data, "*** Failure with %s\r", TNC->Streams[Stream].RemoteCall); - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // In case! - STREAM->FramesOutstanding = 0; - - if (Stream == 0) - { - sprintf(TNC->WEB_TNCSTATE, "In Use by %s", STREAM->MyCall); - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - } - - STREAM->ReportDISC = TRUE; // Tell Node - return; - } - - // Must Have been connected or disconnecting - Release Session - - STREAM->Connecting = FALSE; - STREAM->Connected = FALSE; // Back to Command Mode - STREAM->FramesOutstanding = 0; - - if (STREAM->Disconnecting == FALSE) - STREAM->ReportDISC = TRUE; // Tell Node - - STREAM->Disconnecting = FALSE; - return; - } - - if (strstr(Buffer, "CONNECTED")) - { - char * Call = strstr(Buffer, " to "); - char * ptr; - char MHCall[30]; - - // Do we need to protect against 2nd call in Dragon Single Mode??? - - Call += 4; - - if (Call[1] == ':') - Call +=2; - - ptr = strchr(Call, ' '); - if (ptr) *ptr = 0; - - ptr = strchr(Call, 13); - if (ptr) *ptr = 0; - - STREAM->Connected = TRUE; // Subsequent data to data channel - STREAM->Connecting = FALSE; - STREAM->ConnectTime = time(NULL); - STREAM->BytesRXed = STREAM->BytesTXed = 0; - - // Stop Scanner - - if (Stream == 0 || TNC->HFPacket) - { - TNC->SwitchToPactor = 0; // Cancel any RP to Pactor switch - - sprintf(Status, "%d SCANSTOP", TNC->Port); - Rig_Command((TRANSPORTENTRY *) -1, Status); - - SuspendOtherPorts(TNC); // Prevent connects on other ports in same scan gruop - - memcpy(MHCall, Call, 9); - MHCall[9] = 0; - } - - if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] == 0) - { - // Incoming Connect - - TNC->SessionTimeLimit = TNC->DefaultSessionTimeLimit; // Reset Limit - - // Check for ExcludeList - - if (ExcludeList[0]) - { - UCHAR AXCALL[7]; - - ConvToAX25(MHCall, AXCALL); //Permitted calls are stored in ax.25 format - - if (CheckExcludeList(AXCALL) == FALSE) - { - TidyClose(TNC, Stream); - sprintf(Status, "%d SCANSTART 15", TNC->Port); - Rig_Command((TRANSPORTENTRY *) -1, Status); - Debugprintf("SCS Call from %s rejected", MHCall); - return; - } - } - - // IF WE HAVE A PERMITTED CALLS LIST, SEE IF HE IS IN IT - - if (TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS) - { - UCHAR * ptr = TNC->PortRecord->PORTCONTROL.PERMITTEDCALLS; - UCHAR AXCALL[7]; - - ConvToAX25(MHCall, AXCALL); //Permitted calls are stored in ax.25 format - - while (TRUE) - { - if (memcmp(AXCALL, ptr, 6) == 0) // Ignore SSID - break; - - ptr += 7; - - if ((*ptr) == 0) // Not in list - { - char Status[64]; - - TidyClose(TNC, 0); - sprintf(Status, "%d SCANSTART 15", TNC->Port); - Rig_Command((TRANSPORTENTRY *) -1, Status); - Debugprintf("Pactor Call from %s not in ValidCalls - rejected", Call); - return; - } - } - } - - // Check that we think we are in the right mode - - if (Stream == 0 && TNC->Dragon == 0) // Dragon runs both at the same time - { - if (TNC->HFPacket && RealStream == 31) - { - Debugprintf("Incoming Pactor Call while in Packet Mode"); - TNC->HFPacket = FALSE; - STREAM->DEDStream = 31; - } - else - if (TNC->HFPacket == 0 && RealStream == 30) - { - Debugprintf("Incoming Packet Call while in Pactor Mode"); - TNC->HFPacket = TRUE; - STREAM->DEDStream = 30; - } - } - - if (TNC->HFPacket) - { - char Save = TNC->RIG->CurrentBandWidth; - TNC->RIG->CurrentBandWidth = 'R'; - UpdateMH(TNC, MHCall, '+', 'I'); - TNC->RIG->CurrentBandWidth = Save; - } - - memcpy(STREAM->RemoteCall, Call, 9); // Save Text Callsign - - // We need to check what MYCALL is set to, either in case - // Appl Scan has failed to change the callsign or if a - // Packet Call to MYALIAS - - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - sprintf(STREAM->CmdSet, "I\r"); - - STREAM->CheckingCall = TRUE; - return; - } - else - { - // Connect Complete - - buffptr = GetBuff(); - if (buffptr == 0) return; // No buffers, so ignore - - buffptr->Len = sprintf(buffptr->Data, "*** Connected to %s\r", Call);; - - C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr); - - if (Stream == 0) - { - if (TNC->RIG) - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound Freq %s", STREAM->MyCall, STREAM->RemoteCall, TNC->RIG->Valchar); - else - sprintf(TNC->WEB_TNCSTATE, "%s Connected to %s Outbound", STREAM->MyCall, STREAM->RemoteCall); - - SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE); - - if (STREAM->DEDStream == 30) // Robust Mode - { - char Save = TNC->RIG->CurrentBandWidth; - TNC->RIG->CurrentBandWidth = 'R'; - UpdateMH(TNC, Call, '+', 'O'); - TNC->RIG->CurrentBandWidth = Save; - } - else - { - UpdateMH(TNC, Call, '+', 'O'); - } - } - return; - } - } - return; - } - - if (Msg[3] == 4 || Msg[3] == 5) - { - struct STREAMINFO * STREAM = &TNC->Streams[1]; // RP Stream - - // Monitor - - if ((TNC->HFPacket || TNC->DragonSingle) && TNC->UseAPPLCalls && strstr(&Msg[4], "SABM") && STREAM->Connected == FALSE) - { - // See if a call to Nodecall or one of our APPLCALLS - if so, stop scan and switch MYCALL - - char DestCall[10] = "NOCALL "; - char * ptr1 = strstr(&Msg[7], "to "); - int i; - APPLCALLS * APPL; - char Appl[11]; - char Status[80]; - - if (ptr1) memcpy(DestCall, &ptr1[3], 10); - - ptr1 = strchr(DestCall, ' '); - if (ptr1) *(ptr1) = 0; // Null Terminate - - Debugprintf("RP SABM Received for %s" , DestCall); - - if (strcmp(TNC->NodeCall, DestCall) != 0) - { - // Not Calling NodeCall/Portcall - - if (strcmp(NodeCall, DestCall) == 0) - goto SetThisCall; - - // See if to one of our ApplCalls - - for (i = 0; i < 32; i++) - { - APPL=&APPLCALLTABLE[i]; - - if (APPL->APPLCALL_TEXT[0] > ' ') - { - char * ptr; - memcpy(Appl, APPL->APPLCALL_TEXT, 10); - ptr=strchr(Appl, ' '); - - if (ptr) *ptr = 0; - - if (strcmp(Appl, DestCall) == 0) - { - SetThisCall: - Debugprintf("RP SABM is for NODECALL or one of our APPLCalls - setting MYCALL to %s and pausing scan", DestCall); - - sprintf(Status, "%d SCANSTART 30", TNC->Port); - Rig_Command((TRANSPORTENTRY *) -1, Status); - TNC->SwitchToPactor = 0; // Stay in RP - - strcpy(STREAM->MyCall, DestCall); - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - sprintf(STREAM->CmdSet, "I%s\r", DestCall); - TNC->InternalCmd = TRUE; - - break; - } - } - } - } - } - - DoMonitor(TNC, &Msg[3], framelen - 3); - return; - - } - - // 1, 2, 4, 5 - pass to Appl - - buffptr = GetBuff(); - - if (buffptr == NULL) return; // No buffers, so ignore - - buffptr->Len = sprintf(buffptr->Data,"Pactor} %s", &Msg[4]); - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Msg[4], (int)strlen(&Msg[4])); - CloseLogFile(TNC->Port); - - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return; - } - - if (Msg[3] == 6) - { - // Monitor Data With length) - - DoMonitor(TNC, &Msg[3], framelen - 3); - return; - } - - if (Msg[3] == 7) - { - char StatusMsg[60]; - int Status, ISS, Offset; - - if (Msg[2] == 0xfe) // Status Poll Response - { - int PactorLevel = Msg[6] & 7; // Pactor Level 1-4 - - if (TNC->MinLevelTimer) - { - if (PactorLevel >= TNC->MinLevel) - { - Debugprintf("Reached MIN Pactor Level"); - TNC->MinLevelTimer = 0; - } - else - Debugprintf("Still waiting for Min Level Now %d Need %d", PactorLevel, TNC->MinLevel); - } - - Status = Msg[5]; - - TNC->Streams[0].PTCStatus0 = Status; - TNC->Streams[0].PTCStatus1 = PactorLevel; // Pactor Level 1-4 - TNC->Streams[0].PTCStatus2 = Msg[7]; // Speed Level - Offset = Msg[8]; - - if (Offset > 128) - Offset -= 128; - - TNC->Streams[0].PTCStatus3 = Offset; - - TNC->Mode = (Status >> 4) & 7; - ISS = Status & 8; - Status &= 7; - - if (TNC->PTCStatus != Status) // Changed - { - Debugprintf("SCS status changed, now %s", status[Status]); - - if (Status == 6) // SYNCH - { - // New Sync - - if (TNC->RIG->RIG_DEBUG) - Debugprintf("SCS New SYNC Detected"); - - TNC->TimeEnteredSYNCMode = time(NULL); - TNC->SyncSupported = TRUE; - } - else - { - if (TNC->PTCStatus == 6) - { - if (TNC->RIG->RIG_DEBUG) - Debugprintf("SCS left SYNC, now %s", status[Status]); - - TNC->TimeEnteredSYNCMode = 0; - } - } - TNC->PTCStatus = Status; - } - sprintf(StatusMsg, "%x %x %x %x", TNC->Streams[0].PTCStatus0, - TNC->Streams[0].PTCStatus1, TNC->Streams[0].PTCStatus2, TNC->Streams[0].PTCStatus3); - - if (ISS) - { - SetWindowText(TNC->xIDC_TXRX, "Sender"); - strcpy(TNC->WEB_TXRX, "Sender"); - } - else - { - SetWindowText(TNC->xIDC_TXRX, "Receiver"); - strcpy(TNC->WEB_TXRX, "Receiver"); - } - - SetWindowText(TNC->xIDC_STATE, status[Status]); - strcpy(TNC->WEB_STATE, status[Status]); - SetWindowText(TNC->xIDC_MODE, ModeText[TNC->Mode]); - strcpy(TNC->WEB_MODE, ModeText[TNC->Mode]); - - if (TNC->Mode == 7) - TNC->Busy = TNC->BusyHold * 10; // BusyHold delay - - if (Offset == 128) // Undefined - sprintf(StatusMsg, "Mode %s Speed Level %d Freq Offset Unknown", - PactorLevelText[TNC->Streams[0].PTCStatus1], Msg[7]); - else - sprintf(StatusMsg, "Mode %s Speed Level %d Freq Offset %d", - PactorLevelText[TNC->Streams[0].PTCStatus1], Msg[7], Offset); - - strcpy(TNC->WEB_PACTORLEVEL, StatusMsg); - SetWindowText(TNC->xIDC_PACTORLEVEL, StatusMsg); - - return; - } - - if (Msg[2] == 248) // Log Message - { - // Monitor Data - Length format - // first 4 bytes contain a 32 bits long timestamp. - // That timestamp holds the number of seconds that elapsed since date 01.01.2000 at 00:00:00. - // The MS byte is sent first. The timestamp can be corrected to the usual C timestamp (seconds - //since 01.01.1970, 00:00:00) simply by adding 946684800 (seconds) to it. - // Teminated with LF - - int datalen = Msg[4] + 1; - unsigned int timestamp = (Msg[5] << 24) + (Msg[6] << 16) - + (Msg[6] << 8) + Msg[7] + 946684800; - - Msg[5 + datalen] = 0; - Debugprintf("SCS Debug %s", &Msg[9]); - return; - } - - if (Msg[2] == 253) // Rig Port Response - { - // Queue for Rig Control Driver - - int datalen = Msg[4] + 1; - PMSGWITHLEN buffptr; - - // if not configured to use PTC Rig Control, Ignore - - if (TNC->RIG->PORT == NULL || TNC->RIG->PORT->PTC == NULL) - return; - - buffptr = GetBuff(); - - if (buffptr) - { - buffptr->Len = datalen; - memcpy(buffptr->Data, &Msg[5], datalen); - C_Q_ADD(&TNC->RadiotoBPQ_Q, buffptr); - if (TNC->RIG->RIG_DEBUG) - { - Debugprintf("SCS RIG frame received, len %d", datalen); - Debugprintf("%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", - Msg[5], Msg[6], Msg[7], Msg[8], Msg[9], Msg[10], Msg[11], Msg[12], - Msg[13], Msg[14], Msg[15], Msg[16], Msg[17], Msg[18], Msg[19], Msg[20]); - - } - } - return; - } - - // Connected Data - - buffptr = GetBuff(); - - if (buffptr == NULL) return; // No buffers, so ignore - - buffptr->Len = Msg[4] + 1; // Length - TNC->Streams[Stream].BytesRXed += (int)buffptr->Len; - memcpy(buffptr->Data, &Msg[5], buffptr->Len); - - WritetoTrace(TNC, &Msg[5], (int)buffptr->Len); - - C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); - - return; - } -} - -int GetPTCRadioCommand(struct TNCINFO * TNC, char * Block) -{ - PMSGWITHLEN buffptr; - int Length; - - if (TNC->RadiotoBPQ_Q == 0) - return 0; - - buffptr = Q_REM(&TNC->RadiotoBPQ_Q); - - Length = (int)buffptr->Len; - - memcpy(Block, buffptr->Data, Length); - - ReleaseBuffer(buffptr); - -// Debugprintf("SCS Rig Command Queued"); - - return Length;; -} - -int SendPTCRadioCommand(struct TNCINFO * TNC, char * Block, int Length) -{ - PMSGWITHLEN buffptr; - - if (TNC->TNCOK || (TNC->Hardware == H_ARDOP && TNC->ARDOPCommsMode == 'T')) - { - } - else - return 0; - - // Queue for TNC - - buffptr = GetBuff(); - - if (buffptr == 0) return (0); // No buffers, so ignore - - buffptr->Len = Length; - - memcpy(buffptr->Data, Block, Length); - - C_Q_ADD(&TNC->BPQtoRadio_Q, buffptr); - - return 0; - -} - -static MESSAGE Monframe; // I frames come in two parts. - -#define TIMESTAMP 352 - -MESSAGE * AdjMsg = &Monframe; // Adjusted for digis - -static VOID DoMonitor(struct TNCINFO * TNC, UCHAR * Msg, int Len) -{ - // Convert to ax.25 form and pass to monitor - - UCHAR * ptr, * starptr; - char * context; - char * MHCall = Monframe.ORIGIN; - - - if (Msg[0] == 6) // Second part of I or UI - { - int len = Msg[1] +1; - - memcpy(AdjMsg->L2DATA, &Msg[2], len); - Monframe.LENGTH += len; - - time(&Monframe.Timestamp); - - BPQTRACE((MESSAGE *)&Monframe, TRUE); - return; - } - - Monframe.LENGTH = MSGHDDRLEN + 16; // Control Frame - - Monframe.PORT = TNC->Port; - - AdjMsg = &Monframe; // Adjusted for digis - ptr = strstr(Msg, "fm "); - - ConvToAX25(&ptr[3], Monframe.ORIGIN); - - ptr = strstr(ptr, "to "); - - ConvToAX25(&ptr[3], Monframe.DEST); - - ptr = strstr(ptr, "via "); - - if (ptr) - { - // We have digis - - char Save[100]; - char * fiddle; - - memcpy(Save, &ptr[4], 60); - - ptr = strtok_s(Save, " ", &context); -DigiLoop: - fiddle = (char *)AdjMsg; - fiddle += 7; - AdjMsg = (MESSAGE *)fiddle; - - Monframe.LENGTH += 7; - - starptr = strchr(ptr, '*'); - if (starptr) - *(starptr) = 0; - - ConvToAX25(ptr, AdjMsg->ORIGIN); - - if (starptr) - AdjMsg->ORIGIN[6] |= 0x80; // Set end of address - - ptr = strtok_s(NULL, " ", &context); - - if (memcmp(ptr, "ctl", 3)) - goto DigiLoop; - } - - AdjMsg->ORIGIN[6] |= 1; // Set end of address - - ptr = strstr(Msg, "ctl "); - - if (memcmp(&ptr[4], "SABM", 4) == 0) - { - AdjMsg->CTL = 0x2f; - UpdateMHwithDigis(TNC, MHCall, '.', 0); - } - else - if (memcmp(&ptr[4], "DISC", 4) == 0) - AdjMsg->CTL = 0x43; - else - if (memcmp(&ptr[4], "UA", 2) == 0) - { - AdjMsg->CTL = 0x63; - UpdateMHwithDigis(TNC, MHCall, '.', 0); - } - else - if (memcmp(&ptr[4], "DM", 2) == 0) - AdjMsg->CTL = 0x0f; - else - if (memcmp(&ptr[4], "UI", 2) == 0) - { - AdjMsg->CTL = 0x03; - UpdateMHwithDigis(TNC, MHCall, '.', 0); - } - else - if (memcmp(&ptr[4], "RR", 2) == 0) - AdjMsg->CTL = 0x1 | (ptr[6] << 5); - else - if (memcmp(&ptr[4], "RNR", 3) == 0) - AdjMsg->CTL = 0x5 | (ptr[7] << 5); - else - if (memcmp(&ptr[4], "REJ", 3) == 0) - AdjMsg->CTL = 0x9 | (ptr[7] << 5); - else - if (memcmp(&ptr[4], "FRMR", 4) == 0) - AdjMsg->CTL = 0x87; - else - if (ptr[4] == 'I') - { - AdjMsg->CTL = (ptr[5] << 5) | (ptr[6] & 7) << 1 ; - } - - if (strchr(&ptr[4], '+')) - { - AdjMsg->CTL |= 0x10; - Monframe.DEST[6] |= 0x80; // SET COMMAND - } - - if (strchr(&ptr[4], '-')) - { - AdjMsg->CTL |= 0x10; - Monframe.ORIGIN[6] |= 0x80; // SET COMMAND - } - - if (Msg[0] == 5) // More to come - { - ptr = strstr(ptr, "pid "); - sscanf(&ptr[3], "%x", (int *)&AdjMsg->PID); - return; - } - - time(&Monframe.Timestamp); - - BPQTRACE((MESSAGE *)&Monframe, TRUE); - -} -//1:fm G8BPQ to KD6PGI-1 ctl I11^ pid F0 -//fm KD6PGI-1 to G8BPQ ctl DISC+ - -VOID TidyClose(struct TNCINFO * TNC, int Stream) -{ - // Queue it as we may have just sent data - - TNC->Streams[Stream].CmdSet = TNC->Streams[Stream].CmdSave = malloc(100); - sprintf(TNC->Streams[Stream].CmdSet, "D\r"); -} - - -VOID ForcedClose(struct TNCINFO * TNC, int Stream) -{ - // Sending D twice should do a "Dirty Disconnect" - - // Try thst first. If it still doesn't disconnect maybe try restart - - unsigned char Resp[500] = ""; - char * Poll = &TNC->TXBuffer[0]; - - Debugprintf("Failed to disconnect TNC - trying a forced disconnect"); - - // Try Normal Mode DD (Dirty Disconnect) - - // Uses "Hidden" feature where you can send any normal mode command - // in host mode by preceeding with a # - - Poll[2] = 31; - Poll[3] = 0x1; - Poll[4] = 2; - sprintf(&Poll[5], "#DD\r"); // Node \r isn't sent but is there for log - CRCStuffAndSend(TNC, Poll, 8); - - // It looks like there isn't a response - - TNC->Timeout = 0; - - OpenLogFile(TNC->Port); - WriteLogLine(TNC->Port, &Poll[5], 4); - CloseLogFile(TNC->Port); - -/* - Poll[2] = 31; - Poll[3] = 1; - Poll[4] = 0; - Poll[5] = 'D'; - - CRCStuffAndSend(TNC, Poll, 6); - - // Wait for response before sending another - - n = 0; - while (CheckRXHost(TNC, Resp) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - - Poll[2] = 31; - Poll[3] = 1; - Poll[4] = 0; - Poll[5] = 'D'; - - CRCStuffAndSend(TNC, Poll, 6); - - n = 0; - while (CheckRXHost(TNC, Resp) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - - // See if it worked - - Poll[2] = 254; // Channel - Poll[3] = 0x1; // Command - Poll[4] = 1; // Len-1 - Poll[5] = 'G'; // Extended Status Poll - Poll[6] = '3'; - - CRCStuffAndSend(TNC, Poll, 7); - - n = 0; - while (CheckRXHost(TNC, Resp) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - - Debugprintf("PTC Status Now %x %x %x %x %x %x %x %x", - Resp[0], Resp[1], Resp[2], Resp[3], Resp[4], Resp[5], Resp[6], Resp[7]); - - TNC->Timeout = 0; - - return; - - // Maybe best just to restart the TNC - - if (TNC->PacketChannels == 0) // Not using packet - { - Debugprintf("Forced Disconnect Failed - restarting TNC"); - - // Ensure in Pactor - - if(TNC->Dragon == 0) - { - TNC->TXBuffer[2] = 31; - TNC->TXBuffer[3] = 0x1; - TNC->TXBuffer[4] = 0x1; - memcpy(&TNC->TXBuffer[5], "PT", 2); - - CRCStuffAndSend(TNC, TNC->TXBuffer, 7); - - n = 0; - while (CheckRXHost(TNC, Resp) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - } - - Sleep(50); - ExitHost(TNC); - Sleep(50); - - n = 0; - while (CheckRXHost(TNC, Resp) == FALSE) - { - Sleep(5); - n++; - if (n > 100) break; - } - - TNC->Timeout = 0; - TNC->HostMode = FALSE; - TNC->ReinitState = 0; - - return; - } -*/ -} - -VOID CloseComplete(struct TNCINFO * TNC, int Stream) -{ - char Status[80]; - struct STREAMINFO * STREAM = &TNC->Streams[Stream]; - - Debugprintf("SCS Pactor Close Complete - Stream = %d", Stream); - - STREAM->CmdSet = STREAM->CmdSave = malloc(100); - - strcpy(STREAM->MyCall, TNC->NodeCall); - - if (Stream == 0 || TNC->HFPacket) - { - SetWindowText(TNC->xIDC_TNCSTATE, "Free"); - strcpy(TNC->WEB_TNCSTATE, "Free"); - sprintf(Status, "%d SCANSTART 15", TNC->Port); - Rig_Command((TRANSPORTENTRY *) -1, Status); - - if (TNC->Dragon) - { - sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall); - TNC->Streams[0].DEDStream = 31; // Pactor Channel - } - else - { - if (TNC->HFPacket) - { - sprintf(STREAM->CmdSet, "I%s\rPR\r", TNC->NodeCall); - TNC->Streams[0].DEDStream = 30; // Packet Channel - Debugprintf("BPQ32 Session Closed - switch to Packet"); - } - else - { - sprintf(STREAM->CmdSet, "I%s\rPT\r", TNC->NodeCall); - TNC->Streams[0].DEDStream = 31; // Pactor Channel - Debugprintf("BPQ32 Session Closed - switch to Pactor"); - } - } - ReleaseOtherPorts(TNC); - } - else - sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall); - - Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet); - -} - -VOID PTCSuspendPort(struct TNCINFO * TNC, struct TNCINFO * ThisTNC) -{ - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - STREAM->CmdSet = STREAM->CmdSave = zalloc(100); - sprintf(STREAM->CmdSet, "I%s\r", "SCSPTC"); // Should prevent connects - - Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet); -} - -VOID PTCReleasePort(struct TNCINFO * TNC) -{ - struct STREAMINFO * STREAM = &TNC->Streams[0]; - - STREAM->CmdSet = STREAM->CmdSave = zalloc(100); - - if (TNC->UseAPPLCallsforPactor && TNC->RIG && TNC->RIG != &TNC->DummyRig - && TNC->RIG->FreqPtr[0]->APPLCALL[0]) - sprintf(STREAM->CmdSet, "I%s\r", TNC->RIG->FreqPtr[0]->APPLCALL); - else - sprintf(STREAM->CmdSet, "I%s\r", TNC->NodeCall); - - Debugprintf("SCS Pactor CMDSet = %s", STREAM->CmdSet); -} - - - diff --git a/SerialPort.c b/SerialPort.c index 59ab627..9886be7 100644 --- a/SerialPort.c +++ b/SerialPort.c @@ -452,8 +452,7 @@ ok: if (buffptr == 0) return (0); // No buffers, so ignore - buffptr->Len = 36; - memcpy(&buffptr->Data[0], "No Connection to TNC\r", 36); + buffptr->Len = sprintf(&buffptr->Data[0], "No Connection to TNC\r"); C_Q_ADD(&TNC->Streams[Stream].PACTORtoBPQ_Q, buffptr); diff --git a/TelnetV6.c b/TelnetV6.c index b139fad..eb8f9a1 100644 --- a/TelnetV6.c +++ b/TelnetV6.c @@ -427,6 +427,7 @@ int ProcessLine(char * buf, int Port) TCP->MaxSessions = 10; // Default Values TNC->Hardware = H_TELNET; TCP->IPV4 = TRUE; + TCP->SecureTelnet = 1; strcpy(TCP->CMSServer, "cms.winlink.org"); } diff --git a/VARA.c b/VARA.c index 6d1ec68..f83adb1 100644 --- a/VARA.c +++ b/VARA.c @@ -2586,7 +2586,7 @@ VOID VARAProcessDataPacket(struct TNCINFO * TNC, UCHAR * Data, int Length) STREAM->BytesRXed += Length; Data[Length] = 0; - Debugprintf("VARA: RXD %d bytes", Length); +// Debugprintf("VARA: RXD %d bytes", Length); sprintf(TNC->WEB_TRAFFIC, "Sent %d RXed %d Queued %d", STREAM->BytesTXed, STREAM->BytesRXed,STREAM->BytesOutstanding); diff --git a/Versions.h b/Versions.h index 2fd8eb3..332f2ea 100644 --- a/Versions.h +++ b/Versions.h @@ -10,14 +10,14 @@ #endif -#define KVers 6,0,24,40 -#define KVerstring "6.0.24.40\0" +#define KVers 6,0,24,42 +#define KVerstring "6.0.24.42\0" #ifdef CKernel #define Vers KVers #define Verstring KVerstring -#define Datestring "January 2024" +#define Datestring "August 2024" #define VerComments "G8BPQ Packet Switch (C Version)" KVerstring #define VerCopyright "Copyright © 2001-2024 John Wiseman G8BPQ\0" #define VerDesc "BPQ32 Switch\0" diff --git a/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user b/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/WinRPRHelper.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user b/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user new file mode 100644 index 0000000..0cd9a72 --- /dev/null +++ b/WinmorControl.vcproj.LAPTOP-Q6S4RP5Q.johnw.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/WinmorControl.vcproj.NOTTSDESKTOP.John.user b/WinmorControl.vcproj.NOTTSDESKTOP.John.user new file mode 100644 index 0000000..fa82c00 --- /dev/null +++ b/WinmorControl.vcproj.NOTTSDESKTOP.John.user @@ -0,0 +1,65 @@ + + + + + + + + + + + diff --git a/bpqchat.c b/bpqchat.c index 06fb369..35f62c9 100644 --- a/bpqchat.c +++ b/bpqchat.c @@ -70,8 +70,9 @@ // Allow /History to be shortened to /Hi (45) // Fix extra r charater in Chat Config Web Page +//.25 -// Increase sise of status display buffers (7) +// Increase size of status display buffers (7) #include "BPQChat.h" #include "Dbghelp.h" diff --git a/bpqmail.h b/bpqmail.h index 7b72ea4..48270a1 100644 --- a/bpqmail.h +++ b/bpqmail.h @@ -1194,8 +1194,7 @@ int CountMessagestoForward(struct UserInfo * user); VOID * GetMultiLineDialogParam(HWND hDialog, int DLGItem); -#define LIBCONFIG_STATIC -#include "libconfig.h" + VOID * GetMultiStringValue(config_setting_t * hKey, char * ValueName); VOID * RegGetMultiStringValue(HKEY hKey, char * ValueName); diff --git a/tncinfo.h b/tncinfo.h index fa8f4c9..bd0639e 100644 --- a/tncinfo.h +++ b/tncinfo.h @@ -225,6 +225,8 @@ struct STREAMINFO char AGWKey[21]; // Session Key for AGW Session Based Drivers time_t ConnectTime; // Time connection made + time_t AttachTime; + int BytesTXed; int BytesAcked; int BytesRXed; @@ -258,6 +260,7 @@ struct STREAMINFO HWND xIDC_DIRN; int RelaySyncStream; + int VaraACMode; }; typedef struct AGWINFO @@ -409,7 +412,7 @@ struct FreeDataINFO char * SSIDS[16]; }; - +struct sixPackInfo; typedef struct TNCINFO { @@ -427,6 +430,9 @@ typedef struct TNCINFO time_t SessionTimeLimit; // Optional limit to total session time time_t DefaultSessionTimeLimit; // Configured value + time_t AttachTimeLimit; // to trap port left attached for a long time without other activity + time_t AttachTime; + int Hardware; // Hardware Type #define H_WINMOR 1 @@ -449,6 +455,7 @@ typedef struct TNCINFO #define H_WINRPR 17 #define H_HSMODEM 18 #define H_FREEDATA 19 +#define H_SIXPACK 20 int Port; // BPQ Port Number @@ -839,6 +846,8 @@ typedef struct TNCINFO char * NRNeighbour; int NRCloseTimer; struct _LINKTABLE * DummyLink; // Simulated link to simplify interface to ax,25 netrom code + struct sixPackPortInfo * sixPack; + int VaraACMode; } *PTNCINFO; diff --git a/upnp.c b/upnp.c index dbc7c8d..96cb9d3 100644 --- a/upnp.c +++ b/upnp.c @@ -85,6 +85,7 @@ char * leaseDuration = NULL; struct UPNPDev * devlist = 0; char lanaddr[64] = "unset"; /* my ip address on the LAN */ +char wanaddr[64] = "unset"; /* my ip address on the LAN */ struct UPNPUrls urls; struct IGDdatas data; @@ -126,7 +127,11 @@ int upnpInit() return 0; } +#if MINIUPNPC_API_VERSION == 18 + i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), wanaddr, sizeof(wanaddr)); +#else i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); +#endif } AddMap(devlist->descURL, Config->LANport, Config->WANPort, Config->Protocol); @@ -153,7 +158,11 @@ int upnpClose() return 0; } +#if MINIUPNPC_API_VERSION == 18 + i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr), wanaddr, sizeof(wanaddr)); +#else i = UPNP_GetValidIGD(devlist, &urls, &data, lanaddr, sizeof(lanaddr)); +#endif } DeleteMap(devlist->descURL, Config->LANport, Config->WANPort, Config->Protocol);