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);