From 2af4cf380bc7e1b97d719ea18b2c0e0d53386e72 Mon Sep 17 00:00:00 2001
From: g8bpq Sorry, User or Password is invalid - please try again Sorry, No sessions available - please try later "
+ "Select Required Template from %sKAM Pactor Status
");
+
+ Len += sprintf(&Buff[Len], "");
+
+ Len += sprintf(&Buff[Len], "
");
+
+ Len += sprintf(&Buff[Len], "", TNC->WebBuffer);
+ Len = DoScanLine(TNC, Buff, Len);
+
+ return Len;
+}
+
+
+void * KAMExtInit(EXTPORTDATA * PortEntry)
+{
+ char msg[500];
+ struct TNCINFO * TNC;
+ int port;
+ char * ptr;
+ char * TempScript;
+
+ port=PortEntry->PORTCONTROL.PORTNUMBER;
+
+ sprintf(msg,"KAM Pactor %s", PortEntry->PORTCONTROL.SerialPortName);
+ WritetoConsole(msg);
+
+ 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->PortRecord = PortEntry;
+
+ TNC->PortRecord->PORTCONTROL.HWType = TNC->Hardware = H_KAM;
+
+ if (TNC->BusyWait == 0)
+ TNC->BusyWait = 10;
+
+ PortEntry->MAXHOSTMODESESSIONS = 11; // Default
+
+
+ if (PortEntry->PORTCONTROL.PORTCALL[0] == 0)
+ memcpy(TNC->NodeCall, MYNODECALL, 10);
+ else
+ ConvFromAX25(&PortEntry->PORTCONTROL.PORTCALL[0], TNC->NodeCall);
+
+ PortEntry->PORTCONTROL.PROTOCOL = 10; // WINMOR/Pactor
+ PortEntry->PORTCONTROL.PORTQUALITY = 0;
+ PortEntry->SCANCAPABILITIES = NONE; // No Scan Control
+
+ if (PortEntry->PORTCONTROL.PORTINTERLOCK && TNC->RXRadio == 0 && TNC->TXRadio == 0)
+ TNC->RXRadio = TNC->TXRadio = PortEntry->PORTCONTROL.PORTINTERLOCK;
+
+ if (PortEntry->PORTCONTROL.PORTPACLEN == 0)
+ PortEntry->PORTCONTROL.PORTPACLEN = 100;
+
+ PortEntry->PORTCONTROL.PORTSTARTCODE = KAMStartPort;
+ PortEntry->PORTCONTROL.PORTSTOPCODE = KAMStopPort;
+
+// TNC->SuspendPortProc = KAMSuspendPort;
+// TNC->ReleasePortProc = KAMReleasePort;
+
+
+
+ ptr=strchr(TNC->NodeCall, ' ');
+ if (ptr) *(ptr) = 0; // Null Terminate
+
+ // Set Essential Params and MYCALL
+
+ TempScript = malloc(4000);
+
+ strcpy(TempScript, "MARK 1400\r");
+ strcat(TempScript, "SPACE 1600\r");
+ strcat(TempScript, "SHIFT MODEM\r");
+ strcat(TempScript, "INV ON\r");
+ strcat(TempScript, "PTERRS 30\r"); // Default Retries
+ strcat(TempScript, "MAXUSERS 1/10\r");
+ strcat(TempScript, TNC->InitScript);
+
+ free(TNC->InitScript);
+ TNC->InitScript = TempScript;
+
+ // Others go on end so they can't be overriden
+
+ strcat(TNC->InitScript, "ECHO OFF\r");
+ strcat(TNC->InitScript, "XMITECHO ON\r");
+ strcat(TNC->InitScript, "TXFLOW OFF\r");
+ strcat(TNC->InitScript, "XFLOW OFF\r");
+ strcat(TNC->InitScript, "TRFLOW OFF\r");
+ strcat(TNC->InitScript, "AUTOCR 0\r");
+ strcat(TNC->InitScript, "AUTOLF OFF\r");
+ strcat(TNC->InitScript, "CRADD OFF\r");
+ strcat(TNC->InitScript, "CRSUP OFF\r");
+ strcat(TNC->InitScript, "CRSUP OFF/OFF\r");
+ strcat(TNC->InitScript, "LFADD OFF/OFF\r");
+ strcat(TNC->InitScript, "LFADD OFF\r");
+ strcat(TNC->InitScript, "LFSUP OFF/OFF\r");
+ strcat(TNC->InitScript, "LFSUP OFF\r");
+ strcat(TNC->InitScript, "RING OFF\r");
+ strcat(TNC->InitScript, "ARQBBS OFF\r");
+
+ // Set the ax.25 MYCALL
+
+
+ sprintf(msg, "MYCALL %s/%s\r", TNC->NodeCall, TNC->NodeCall);
+ strcat(TNC->InitScript, msg);
+
+ // look for the MAXUSERS config line, and get the limits
+
+ TNC->InitScript = _strupr(TNC->InitScript);
+
+ ptr = strstr(TNC->InitScript, "MAXUSERS");
+
+ if (ptr)
+ {
+ ptr = strchr(ptr,'/'); // to the separator
+ if (ptr)
+ PortEntry->MAXHOSTMODESESSIONS = atoi(++ptr) + 1;
+ }
+
+ if (PortEntry->MAXHOSTMODESESSIONS > 26)
+ PortEntry->MAXHOSTMODESESSIONS = 26;
+
+ 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->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", "Free Space", 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->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;
+
+ MoveWindows(TNC);
+#endif
+ OpenCOMMPort(TNC, PortEntry->PORTCONTROL.SerialPortName, PortEntry->PORTCONTROL.BAUDRATE, FALSE);
+
+ WritetoConsole("\n");
+
+ return ExtProc;
+}
+
+
+
+void CheckRXKAM(struct TNCINFO * TNC)
+{
+ int Length, Len;
+ char debug[512] = "RX: ";
+
+ // only try to read number of bytes in queue
+
+ 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;
+
+ memcpy(&debug[4], TNC->RXBuffer, TNC->RXLen);
+ debug[TNC->RXLen + 4] = 0;
+ WriteLogLine(TNC->Port, debug, TNC->RXLen + 4);
+
+ Length = TNC->RXLen;
+
+ // If first char != FEND, then probably a Terminal Mode Frame. Wait for CR on end
+
+ if (TNC->RXBuffer[0] != FEND)
+ {
+ // 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->RXBuffer[TNC->RXLen-2] != ':')
+ if (strstr(TNC->RXBuffer, "cmd:") == 0)
+ return; // Wait for rest of frame
+
+ // Complete Char Mode Frame
+
+ 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 (TNC->HostMode == 0) // If we are in Term Mode, discard it. Probably in recovery
+ {
+ TNC->RXLen = 0; // Ready for next frame
+ return;
+ }
+
+ if (Length < 3) // Minimum Frame Sise
+ return;
+
+ if (TNC->RXBuffer[Length-1] != FEND)
+ return; // Wait till we have a full frame
+
+ ProcessHostFrame(TNC, TNC->RXBuffer, Length); // Could have multiple packets in buffer
+
+ TNC->RXLen = 0; // Ready for next frame
+
+
+ return;
+
+}
+
+VOID ProcessHostFrame(struct TNCINFO * TNC, UCHAR * rxbuffer, int Len)
+{
+ UCHAR * FendPtr;
+ int NewLen;
+
+ // Split into KISS Packets. By far the most likely is a single KISS frame
+ // so treat as special case
+
+ if (rxbuffer[1] == FEND) // Two FENDS - probably got out of sync
+ {
+ rxbuffer++;
+ Len--;
+ }
+
+ FendPtr = memchr(&rxbuffer[1], FEND, Len-1);
+
+ if (FendPtr == &rxbuffer[Len-1])
+ {
+ ProcessKHOSTPacket(TNC, &rxbuffer[1], Len - 2);
+ return;
+ }
+
+ // Process the first Packet in the buffer
+
+ NewLen = (int)(FendPtr - rxbuffer - 1);
+
+ ProcessKHOSTPacket(TNC, &rxbuffer[1], NewLen);
+
+ // Loop Back
+
+ ProcessHostFrame(TNC, FendPtr+1, Len - NewLen - 2);
+ return;
+
+}
+
+
+
+static BOOL WriteCommBlock(struct TNCINFO * TNC)
+{
+ char debug[512] = "TX: ";
+
+ memcpy(&debug[4], TNC->TXBuffer, TNC->TXLen);
+ debug[TNC->TXLen + 4] = 0;
+
+ WriteLogLine(TNC->Port, debug, TNC->TXLen + 4);
+
+ WriteCOMBlock(TNC->hDevice, TNC->TXBuffer, TNC->TXLen);
+
+ return TRUE;
+}
+
+VOID KAMPoll(int Port)
+{
+ struct TNCINFO * TNC = TNCInfo[Port];
+ struct STREAMINFO * STREAM;
+
+ UCHAR * Poll = TNC->TXBuffer;
+ char Status[80];
+ int Stream;
+
+ if (TNC->PortRecord == 0)
+ Stream = 0;
+
+
+ // If Pactor Session has just been attached, drop back to cmd mode and set Pactor Call to
+ // the connecting user's callsign
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream] && STREAM->Attached == 0)
+ {
+ // New Attach
+
+ STREAM->Attached = TRUE;
+
+ if (Stream == 0) // HF Port
+ {
+ int calllen;
+ UCHAR TXMsg[1000] = "D20";
+ int datalen;
+ char Msg[80];
+
+ TNC->HFPacket = FALSE;
+ TNC->TimeInRX = 0;
+
+ calllen = ConvFromAX25(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4USER, TNC->Streams[0].MyCall);
+ TNC->Streams[0].MyCall[calllen] = 0;
+
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+ if (TNC->VeryOldMode)
+ datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->Streams[0].MyCall);
+ else
+ datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->Streams[0].MyCall);
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->InternalCmd = 'M';
+
+ TNC->NeedPACTOR = 0; // Cancel enter Pactor
+
+ sprintf(TNC->WEB_TNCSTATE, "In Use by %s", TNC->Streams[0].MyCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ // Stop Scanning
+
+ sprintf(Msg, "%d SCANSTOP", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Msg);
+
+ }
+ }
+ }
+
+ if (TNC->Timeout)
+ {
+ TNC->Timeout--;
+
+ if (TNC->Timeout) // Still waiting
+ return;
+
+ // Timed Out
+
+ if (TNC->HostMode == 0)
+ {
+ DoTermModeTimeout(TNC);
+ return;
+ }
+
+ // Timed out in host mode - Clear any connection and reinit the TNC
+
+ Debugprintf("KAM PACTOR - Link to TNC Lost");
+ TNC->TNCOK = FALSE;
+ TNC->HostMode = 0;
+ TNC->ReinitState = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE, "%s Open but TNC not responding", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ PMSGWITHLEN buffptr;
+
+ STREAM = &TNC->Streams[Stream];
+
+ if (TNC->PortRecord->ATTACHEDSESSIONS[Stream]) // Connected
+ {
+ STREAM->Connected = FALSE; // Back to Command Mode
+ STREAM->ReportDISC = TRUE; // Tell Node
+ }
+
+ STREAM->FramesQueued = 0;
+
+ while(STREAM->BPQtoPACTOR_Q)
+ {
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ ReleaseBuffer(buffptr);
+ }
+
+ while(STREAM->PACTORtoBPQ_Q)
+ {
+ buffptr=Q_REM(&STREAM->PACTORtoBPQ_Q);
+ ReleaseBuffer(buffptr);
+ }
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ if (STREAM->Attached)
+ CheckForDetach(TNC, Stream, STREAM, TidyClose, ForcedClose, CloseComplete);
+
+ }
+
+ // if we have just restarted or TNC appears to be in terminal mode, run Initialisation Sequence
+
+ if (!TNC->HostMode)
+ {
+ DoTNCReinit(TNC);
+ return;
+ }
+
+ if (TNC->BusyDelay) // Waiting to send connect
+ {
+ // Still Busy?
+
+ if (InterlockedCheckBusy(TNC) == 0)
+ {
+ // No, so send
+
+ EncodeAndSend(TNC, TNC->ConnectCmd, (int)strlen(TNC->ConnectCmd));
+ free(TNC->ConnectCmd);
+
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ STREAM->Connecting = TRUE;
+
+ TNC->Streams[0].Connecting = TRUE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s", TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ 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 = sprintf(buffptr->Data, "Sorry, Can't Connect - Channel is busy\r");
+
+ C_Q_ADD(&TNC->Streams[0].PACTORtoBPQ_Q, buffptr);
+
+ free(TNC->ConnectCmd);
+
+ }
+ }
+ }
+
+ if (TNC->NeedPACTOR)
+ {
+ TNC->NeedPACTOR--;
+
+ if (TNC->NeedPACTOR == 0)
+ {
+ int datalen;
+ UCHAR TXMsg[80] = "D20";
+
+ if (TNC->VeryOldMode)
+ datalen = sprintf(TXMsg, "C20MYCALL %s", TNC->NodeCall);
+ else
+ datalen = sprintf(TXMsg, "C20MYPTCALL %s", TNC->NodeCall);
+ EncodeAndSend(TNC, TXMsg, datalen);
+
+ if (TNC->OldMode)
+ EncodeAndSend(TNC, "C20PACTOR", 9); // Back to Listen
+ else
+ EncodeAndSend(TNC, "C20TOR", 6); // Back to Listen
+
+ TNC->InternalCmd = 'T';
+ TNC->Timeout = 50;
+ TNC->IntCmdDelay--;
+
+ // Restart Scanning
+
+ sprintf(Status, "%d SCANSTART 15", TNC->Port);
+
+ Rig_Command( (TRANSPORTENTRY *) -1, Status);
+
+ return;
+ }
+ }
+
+ for (Stream = 0; Stream <= MaxStreams; Stream++)
+ {
+ STREAM = &TNC->Streams[Stream];
+
+ // If in HF Packet mode, normal flow control doesn't seem to work
+ // If more that 4 packets sent, send a status poll. and use response to
+ // reset frames outstanding
+
+ if ((Stream == 0) && (TNC->HFPacket) && (TNC->Streams[0].FramesOutstanding > 4))
+ {
+ EncodeAndSend(TNC, "C10S", 4);
+ TNC->InternalCmd = 'S';
+ TNC->Timeout = 50;
+ return;
+
+ }
+
+ if (TNC->TNCOK && STREAM->BPQtoPACTOR_Q)
+ {
+ int datalen;
+ UCHAR TXMsg[1000] = "D20";
+ PMSGWITHLEN buffptr;
+ UCHAR * MsgPtr;
+ char Status[80];
+
+ if (STREAM->Connected)
+ {
+ int Next;
+
+ if (Stream > 0)
+ sprintf(TXMsg, "D1%c", Stream + '@');
+ else if (TNC->HFPacket)
+ memcpy(TXMsg, "D2A", 3);
+ else
+ {
+ // Pactor
+
+ // Limit amount in TX, so we keep some on the TX Q and don't send turnround too early
+
+ if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked > 200)
+ continue;
+
+ // Dont send if IRS State
+ // If in IRS state for too long, force turnround
+
+ if (TNC->TXRXState == 'R')
+ {
+ if (TNC->TimeInRX++ > 15)
+ EncodeAndSend(TNC, "T", 1); // Changeover to ISS
+ else
+ goto Poll;
+ }
+ TNC->TimeInRX = 0;
+ }
+
+ buffptr=Q_REM(&STREAM->BPQtoPACTOR_Q);
+ STREAM->FramesQueued--;
+
+ datalen = buffptr->Len;
+ MsgPtr = buffptr->Data;
+
+ if (TNC->SwallowSignon && Stream == 0)
+ {
+ TNC->SwallowSignon = FALSE;
+ if (strstr(MsgPtr, "Connected")) // Discard *** connected
+ {
+ ReleaseBuffer(buffptr);
+ return;
+ }
+ }
+
+ Next = 0;
+ STREAM->bytesTXed += datalen;
+
+ if (Stream == 0)
+ {
+ while (datalen > 100) // Limit Pactor Sends
+ {
+ memcpy(&TXMsg[3], &MsgPtr[Next], 100);
+ EncodeAndSend(TNC, TXMsg, 103);
+ Next += 100;
+ datalen -= 100;
+
+ WritetoTrace(TNC, &TXMsg[3], 100);
+ }
+ }
+
+ memcpy(&TXMsg[3], &MsgPtr[Next], datalen);
+ EncodeAndSend(TNC, TXMsg, datalen + 3);
+
+ WritetoTrace(TNC, &TXMsg[3], datalen);
+
+ ReleaseBuffer(buffptr);
+
+ if (Stream == 0)
+ {
+ sprintf(Status, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, Status);
+
+ if ((TNC->HFPacket == 0) && (TNC->Streams[0].BPQtoPACTOR_Q == 0)) // Nothing following
+ {
+ EncodeAndSend(TNC, "E", 1); // Changeover when all sent
+ }
+ }
+
+ if (STREAM->Disconnecting)
+ {
+ Debugprintf("Send with Disc Pending, Q = %x", STREAM->BPQtoPACTOR_Q);
+ if (STREAM->BPQtoPACTOR_Q == 0) // All Sent
+
+ // KAM doesnt have a tidy close!
+
+ STREAM->DisconnectingTimeout = 100; // Give 5 secs to get to other end
+ }
+ return;
+ }
+ else // Not Connected
+ {
+ buffptr = Q_REM(&STREAM->BPQtoPACTOR_Q);
+ datalen = buffptr->Len;
+ MsgPtr = buffptr->Data;
+
+ // Command. Do some sanity checking and look for things to process locally
+
+ datalen--; // Exclude CR
+ MsgPtr[datalen] = 0; // Null Terminate
+ _strupr(MsgPtr);
+
+ if ((Stream == 0) && memcmp(MsgPtr, "RADIO ", 6) == 0)
+ {
+ sprintf(&MsgPtr[40], "%d %s", TNC->Port, &MsgPtr[6]);
+ if (Rig_Command(TNC->PortRecord->ATTACHEDSESSIONS[0]->L4CROSSLINK, &MsgPtr[40]))
+ {
+ ReleaseBuffer(buffptr);
+ }
+ else
+ {
+ buffptr->Len = sprintf(buffptr->Data, "%s", &MsgPtr[40]);
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ }
+ return;
+ }
+
+ if (_memicmp(MsgPtr, "D\r", 2) == 0)
+ {
+ STREAM->ReportDISC = TRUE; // Tell Node
+ return;
+ }
+
+ if ((Stream == 0) && memcmp(MsgPtr, "HFPACKET", 8) == 0)
+ {
+ TNC->HFPacket = TRUE;
+ buffptr->Len = sprintf(buffptr->Data, "KAM} OK\r");
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+ return;
+ }
+
+ if (MsgPtr[0] == 'C' && MsgPtr[1] == ' ' && datalen > 2) // Connect
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[2], 9);
+ STREAM->Connecting = TRUE;
+
+ // If Stream 0, Convert C CALL to PACTOR CALL
+
+ if (Stream == 0)
+ {
+ if (TNC->HFPacket)
+ datalen = sprintf(TXMsg, "C2AC %s", TNC->Streams[0].RemoteCall);
+ else
+ datalen = sprintf(TXMsg, "C20PACTOR %s", TNC->Streams[0].RemoteCall);
+
+ // If Pactor, check busy detecters on any interlocked ports
+
+ if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
+ {
+ // Channel Busy. Wait
+
+ TNC->ConnectCmd = _strdup(TXMsg);
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = TNC->BusyWait * 10;
+
+ return;
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
+ TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ }
+ else
+ datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
+
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ ReleaseBuffer(buffptr);
+ STREAM->Connecting = TRUE;
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "GTOR ", 5) == 0) // GTOR Connect
+ {
+ memcpy(STREAM->RemoteCall, &MsgPtr[5], 9);
+ STREAM->Connecting = TRUE;
+
+ // If Stream 0, Convert C CALL to PACTOR CALL
+
+ if (Stream == 0)
+ {
+ datalen = sprintf(TXMsg, "C20GTOR %s", TNC->Streams[0].RemoteCall);
+
+ // If Pactor, check busy detecters on any interlocked ports
+
+ if (TNC->HFPacket == 0 && InterlockedCheckBusy(TNC) && TNC->OverrideBusy == 0)
+ {
+ // Channel Busy. Wait
+
+ TNC->ConnectCmd = _strdup(TXMsg);
+
+ sprintf(TNC->WEB_TNCSTATE, "Waiting for clear channel");
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+
+ TNC->BusyDelay = TNC->BusyWait * 10;
+
+ return;
+ }
+
+ TNC->OverrideBusy = FALSE;
+
+ sprintf(TNC->WEB_TNCSTATE, "%s Connecting to %s",
+ TNC->Streams[0].MyCall, TNC->Streams[0].RemoteCall);
+ SetWindowText(TNC->xIDC_TNCSTATE, TNC->WEB_TNCSTATE);
+ }
+ else
+ datalen = sprintf(TXMsg, "C1%cC %s", Stream + '@', STREAM->RemoteCall);
+
+ EncodeAndSend(TNC, TXMsg, datalen);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 'C'; // So we dont send the reply to the user.
+ ReleaseBuffer(buffptr);
+ STREAM->Connecting = TRUE;
+
+ return;
+ }
+
+ if (memcmp(MsgPtr, "DISCONNECT", datalen) == 0) // Disconnect
+ {
+ if (Stream == 0)
+ {
+ if (TNC->HFPacket)
+ EncodeAndSend(TNC, "C2AD", 4); // ??Return to packet mode??
+ else
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+
+ TNC->NeedPACTOR = 50;
+ }
+ else
+ {
+ sprintf(TXMsg, "C1%cD", Stream + '@');
+ EncodeAndSend(TNC, TXMsg, 4);
+ TNC->CmdStream = Stream;
+ TNC->Timeout = 50;
+ }
+
+ TNC->Timeout = 0; // Don't expect a response
+ STREAM->Connecting = FALSE;
+ STREAM->ReportDISC = TRUE;
+ ReleaseBuffer(buffptr);
+
+ return;
+ }
+
+ // Other Command ??
+
+ if (Stream > 0)
+ datalen = sprintf(TXMsg, "C1%c%s", Stream + '@', MsgPtr);
+ else
+ datalen = sprintf(TXMsg, "C20%s", MsgPtr);
+ EncodeAndSend(TNC, TXMsg, datalen);
+ ReleaseBuffer(buffptr);
+ TNC->Timeout = 50;
+ TNC->InternalCmd = 0;
+ TNC->CmdStream = Stream;
+
+ }
+ }
+ }
+
+Poll:
+
+ // Need to poll data and control channel (for responses to commands)
+
+ // Also check status if we have data buffered (for flow control)
+
+ if (TNC->TNCOK)
+ {
+ if (TNC->IntCmdDelay == 50)
+ {
+ EncodeAndSend(TNC, "C10S", 4);
+ TNC->InternalCmd = 'S';
+ TNC->Timeout = 50;
+ TNC->IntCmdDelay--;
+ return;
+ }
+
+ if (TNC->IntCmdDelay <=0)
+ {
+ if (TNC->VeryOldMode == FALSE)
+ {
+ EncodeAndSend(TNC, "?", 1);
+ TNC->InternalCmd = '?';
+ TNC->Timeout = 50;
+ }
+ TNC->IntCmdDelay = 100; // Every 30
+ return;
+ }
+ else
+ TNC->IntCmdDelay--;
+ }
+
+ return;
+
+}
+
+static VOID DoTNCReinit(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 1) // Forcing back to Term
+ TNC->ReinitState = 0; // Got Response, so must be back in term mode
+
+ if (TNC->ReinitState == 0)
+ {
+ // Just Starting - Send a TNC Mode Command to see if in Terminal or Host Mode
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s Initialising TNC", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ Poll[0] = 13;
+ TNC->TXLen = 1;
+
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ return;
+ }
+
+ 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
+
+ memcpy(Poll, "INTFACE HOST\r", 13);
+
+ TNC->TXLen = 13;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ TNC->ReinitState = 4; // Need Reset
+
+ return;
+ }
+
+ end = strchr(start, 13);
+ len = (int)(++end - start);
+ TNC->InitPtr = end;
+ memcpy(Poll, start, len);
+
+ TNC->TXLen = len;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+
+ return;
+
+ }
+}
+
+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;
+ Poll[0] = 3;
+ Poll[1] = 0x58; // ?? Back to cmd: mode ??
+ TNC->TXLen = 2;
+
+ Poll[0] = 0xc0;
+ Poll[1] = 'Q'; // ?? Back to cmd: mode ??
+ Poll[2] = 0xc0;
+ TNC->TXLen = 3;
+
+ WriteCommBlock(TNC);
+
+ 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;
+ return;
+ }
+}
+
+
+
+static VOID ProcessTermModeResponse(struct TNCINFO * TNC)
+{
+ UCHAR * Poll = TNC->TXBuffer;
+
+ if (TNC->ReinitState == 0 || TNC->ReinitState == 1)
+ {
+ // Testing if in Term Mode. It is, so can now send Init Commands
+
+ TNC->InitPtr = TNC->InitScript;
+ TNC->ReinitState = 2;
+ DoTNCReinit(TNC); // Send First Command
+ return;
+ }
+ if (TNC->ReinitState == 2)
+ {
+ // Sending Init Commands
+
+ DoTNCReinit(TNC); // Send Next Command
+ return;
+ }
+
+ if (TNC->ReinitState == 4) // Send INTFACE, Need RESET
+ {
+ TNC->ReinitState = 5;
+
+ memcpy(Poll, "RESET\r", 6);
+
+ TNC->TXLen = 6;
+ WriteCommBlock(TNC);
+ TNC->Timeout = 50;
+ TNC->HostMode = TRUE; // Should now be in Host Mode
+ TNC->NeedPACTOR = 50; // Need to Send PACTOR command after 5 secs
+
+ return;
+ }
+
+ if (TNC->ReinitState == 5) // RESET sent
+ {
+ TNC->ReinitState = 5;
+
+ return;
+ }
+
+
+
+}
+
+VOID ProcessKHOSTPacket(struct TNCINFO * TNC, UCHAR * Msg, int Len)
+{
+ PMSGWITHLEN buffptr;
+ char * Buffer = &Msg[3]; // Data portion of frame
+ char * Call;
+ char Status[80];
+ int Stream = 0;
+ struct STREAMINFO * STREAM;
+
+ // Any valid frame is an ACK
+
+ TNC->TNCOK = TRUE;
+
+ Len = KissDecode(Msg, Msg, Len); // Remove KISS transparency
+
+ if (Msg[1] == '0' && Msg[2] == '0')
+ Stream = 0;
+ else
+ if (Msg[1] == '2') Stream = 0; else Stream = Msg[2] - '@';
+
+ STREAM = &TNC->Streams[Stream];
+
+ // See if Poll Reply or Data
+
+ Msg[Len] = 0; // Terminate
+
+ if (Msg[0] == 'M') // Monitor
+ {
+ DoMonitor(TNC, Msg, Len);
+ return;
+ }
+
+
+ if (Msg[0] == 'E') // Data Echo
+ {
+ if (Msg[1] == '2') // HF Port
+ {
+ if (TNC->Streams[0].bytesTXed)
+ TNC->Streams[0].BytesAcked += Len - 3; // We get an ack before the first send
+
+ sprintf(Status, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, Status);
+
+ if (TNC->Streams[0].bytesTXed - TNC->Streams[0].BytesAcked < 500)
+ TNC->Streams[0].FramesOutstanding = 0;
+ }
+ return;
+ }
+
+ if (Msg[0] == 'D') // Data
+ {
+ // Pass to Appl
+
+ buffptr = GetBuff();
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ Len-=3; // Remove Header
+
+ buffptr->Len = Len; // Length
+ STREAM->bytesRXed += Len;
+ memcpy(buffptr->Data, Buffer, Len);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ if (Stream == 0)
+ {
+ sprintf(TNC->WEB_TRAFFIC, "RX %d TX %d ACKED %d ",
+ TNC->Streams[0].bytesRXed, TNC->Streams[0].bytesTXed, TNC->Streams[0].BytesAcked);
+ SetWindowText(TNC->xIDC_TRAFFIC, TNC->WEB_TRAFFIC);
+ }
+
+ WritetoTrace(TNC, Buffer, Len);
+
+ return;
+ }
+
+
+ if (Msg[0] == 'C') // Command Reponse
+ {
+ TNC->Timeout = 0;
+
+ // See if we need to process locally (Response to our command, Incoming Call, Disconencted, etc
+
+ // See if a response to internal command
+
+ if (TNC->InternalCmd)
+ {
+ // Process it
+
+ if (TNC->InternalCmd == 'S') // Status
+ {
+ char * Line;
+ char * ptr;
+
+ // Message is line giving free bytes, followed by a line for each active (packet) stream
+
+ // FREE BYTES 1366/5094
+ // A/2 #1145(12) CONNECTED to KE7XO-3
+ // S/2 CONNECTED to NLV
+
+ // each line is teminated by CR, and by the time it gets here it is null terminated
+
+ //FREE BYTES 2628
+ //A/H #80(1) CONNECTED to DK0MNL..
+
+ if (TNC->HFPacket)
+ TNC->Streams[0].FramesOutstanding = 0;
+
+ Line = strchr(&Msg[3], 13);
+ if (Line == 0) return;
+
+ *(Line) = 0;
+
+ ptr = strchr(&Msg[13], '/');
+ TNC->Mem1 = atoi(&Msg[13]);
+ if (ptr)
+ TNC->Mem2 = atoi(++ptr);
+ else
+ TNC->Mem2 = 0;
+
+ SetWindowText(TNC->xIDC_BUFFERS, &Msg[14]);
+ strcpy(TNC->WEB_BUFFERS, &Msg[14]);
+
+ while (Line[1] != 0) // End of stream
+ {
+ Stream = Line[1] - '@';
+ STREAM = &TNC->Streams[Stream];
+
+ if (Line[5] == '#')
+ {
+ STREAM->BytesOutstanding = atoi(&Line[6]);
+ ptr = strchr(&Line[6], '(');
+ if (ptr)
+ STREAM->FramesOutstanding = atoi(++ptr);
+ }
+ else
+ {
+ STREAM->BytesOutstanding = 0;
+ STREAM->FramesOutstanding = 0;
+ }
+
+ Line = strchr(&Line[1], 13);
+ }
+ return;
+ }
+ return;
+ }
+
+
+ WritetoTrace(TNC, Buffer, Len);
+
+
+ // Pass to Appl
+
+ Stream = TNC->CmdStream;
+
+
+ buffptr = GetBuff();
+
+ if (buffptr == NULL) return; // No buffers, so ignore
+
+ buffptr->Len = sprintf(buffptr->Data,"KAM} %s", Buffer);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ return;
+ }
+
+ if (Msg[0] == 'I') // ISS/IRS State
+ {
+ if (Msg[2] == '1')
+ {
+ strcpy(TNC->WEB_TXRX, "Sender");
+ SetWindowText(TNC->xIDC_TXRX, "Sender");
+ TNC->TXRXState = 'S';
+ }
+ else
+ {
+ strcpy(TNC->WEB_TXRX, "Receiver");
+ SetWindowText(TNC->xIDC_TXRX, "Receiver");
+ TNC->TXRXState = 'R';
+ }
+ return;
+ }
+
+ if (Msg[0] == '?') // Status
+ {
+ TNC->Timeout = 0;
+ return;
+ }
+
+ if (Msg[0] == 'S') // Status
+ {
+ if (Len < 4)
+ {
+ // Reset Response FEND FEND S00 FEND
+
+ TNC->Timeout = 0;
+
+ sprintf(TNC->WEB_COMMSSTATE,"%s TNC link OK", TNC->PortRecord->PORTCONTROL.SerialPortName);
+ SetWindowText(TNC->xIDC_COMMSSTATE, TNC->WEB_COMMSSTATE);
+
+ return;
+ }
+
+ // Pass to Appl
+
+ if (strstr(Buffer, "STANDBY>") || strstr(Buffer, "*** DISCONNECTED"))
+ {
+ if ((STREAM->Connecting | STREAM->Connected) == 0)
+ {
+ // Not connected or Connecting. Probably response to going into Pactor Listen Mode
+
+ 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", STREAM->RemoteCall);
+
+ C_Q_ADD(&STREAM->PACTORtoBPQ_Q, buffptr);
+
+ STREAM->Connecting = FALSE;
+ STREAM->Connected = FALSE; // In case!
+ STREAM->FramesOutstanding = 0;
+
+ 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;
+
+ if (Stream == 0)
+ {
+ // Need to reset Pactor Call in case it was changed
+
+ EncodeAndSend(TNC, "X", 1); // ??Return to packet mode??
+ TNC->NeedPACTOR = 20;
+ }
+
+ return;
+ }
+
+ if (Msg[2] == '0')
+ Call = strstr(Buffer, " ", TNC->WEB_COMMSSTATE);
+ Len += sprintf(&Buff[Len], "Comms State %s ", TNC->WEB_TNCSTATE);
+ Len += sprintf(&Buff[Len], "TNC State %s ", TNC->WEB_MODE);
+ Len += sprintf(&Buff[Len], "Mode %s ", TNC->WEB_STATE);
+ Len += sprintf(&Buff[Len], "Status %s ", TNC->WEB_TXRX);
+ Len += sprintf(&Buff[Len], "TX/RX State %s ", TNC->WEB_BUFFERS);
+ Len += sprintf(&Buff[Len], "Free Space %s ", TNC->WEB_TRAFFIC);
+ Len += sprintf(&Buff[Len], "Traffic %s BPQ32 Mail Server %s Access
"
+ "Please enter Callsign and Password to access WebMail
"
+ "";
+
+static char MsgInputPage[] = ""
+ "Webmail Interface - Message Input Form
"
+ "";
+
+static char CheckFormMsgPage[] = ""
+ "Webmail Forms Interface - Check Message
"
+ "";
+
+
+extern char * WebMailTemplate;
+extern char * WebMailMsgTemplate;
+extern char * jsTemplate;
+
+static char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+char *longday[] = {"Sunday", "Monday", "Tusday", "Wednesday", "Thusday", "Friday", "Saturday"};
+
+static struct HTTPConnectionInfo * WebSessionList = NULL; // active WebMail sessions
+
+#ifdef LINBPQ
+UCHAR * GetBPQDirectory();
+#endif
+
+void UndoTransparency(char * input);
+
+#ifndef LINBPQ
+
+void UndoTransparency(char * input)
+{
+ char * ptr1, * ptr2;
+ char c;
+ int hex;
+
+ if (input == NULL)
+ return;
+
+ ptr1 = ptr2 = input;
+
+ // Convert any %xx constructs
+
+ while (1)
+ {
+ c = *(ptr1++);
+
+ if (c == 0)
+ break;
+
+ if (c == '%')
+ {
+ c = *(ptr1++);
+ if(isdigit(c))
+ hex = (c - '0') << 4;
+ else
+ hex = (tolower(c) - 'a' + 10) << 4;
+
+ c = *(ptr1++);
+ if(isdigit(c))
+ hex += (c - '0');
+ else
+ hex += (tolower(c) - 'a' + 10);
+
+ *(ptr2++) = hex;
+ }
+ else if (c == '+')
+ *(ptr2++) = 32;
+ else
+ *(ptr2++) = c;
+ }
+ *ptr2 = 0;
+}
+#endif
+
+void ReleaseWebMailStruct(WebMailInfo * WebMail)
+{
+ // release any malloc'ed resources
+
+ if (WebMail == NULL)
+ return;
+
+ FreeWebMailFields(WebMail);
+ free(WebMail);
+ return;
+}
+
+VOID FreeWebMailMallocs()
+{
+ // called when closing. Not really needed, but simplifies tracking down real memory leaks
+
+ struct HTTPConnectionInfo * Session, * SaveNext;
+ int i;
+ Session = WebSessionList;
+
+ while (Session)
+ {
+ SaveNext = Session->Next;
+
+ // Release amy malloc'ed resouces
+
+ ReleaseWebMailStruct(Session->WebMail);
+ free(Session);
+ Session = SaveNext;
+ }
+
+ for (i = 0; i < FormDirCount; i++)
+ {
+ struct HtmlFormDir * Dir = HtmlFormDirs[i];
+
+ int j;
+
+ for (j = 0; j < Dir->FormCount; j++)
+ {
+ free(Dir->Forms[j]->FileName);
+ free(Dir->Forms[j]);
+ }
+
+ if (Dir->DirCount)
+ {
+ struct HtmlFormDir * SubDir;
+
+ int k, l;
+
+ for (l = 0; l < Dir->DirCount; l++)
+ {
+ SubDir = Dir->Dirs[l];
+
+ for (k = 0; k < Dir->Dirs[l]->FormCount; k++)
+ {
+ free(SubDir->Forms[k]->FileName);
+ free(SubDir->Forms[k]);
+ }
+ free(SubDir->DirName);
+ free(SubDir->Forms);
+ free(SubDir->FormSet);
+
+ free(Dir->Dirs[l]);
+ }
+ }
+ free(Dir->DirName);
+ free(Dir->Forms);
+ free(Dir->FormSet);
+ free(Dir);
+ }
+
+ free(HtmlFormDirs);
+ return;
+}
+
+char * initMultipartUnpack(char ** Input)
+{
+ // Check if Multipart and return Boundary. Update Input to first part
+
+ // look through header for Content-Type line, and if multipart
+ // find boundary string.
+
+ char * ptr, * ptr2;
+ char Boundary[128];
+ BOOL Multipart = FALSE;
+
+ ptr = *Input;
+
+ while(*ptr != 13)
+ {
+ ptr2 = strchr(ptr, 10); // Find CR
+
+ while(ptr2[1] == ' ' || ptr2[1] == 9) // Whitespace - continuation line
+ ptr2 = strchr(&ptr2[1], 10); // Find CR
+
+ if (_memicmp(ptr, "Content-Type: ", 14) == 0)
+ {
+ char Line[256] = "";
+ char * ptr3;
+ size_t len = ptr2-ptr-14;
+
+ if (len >255)
+ return NULL;
+
+ memcpy(Line, &ptr[14], len);
+
+ if (_memicmp(Line, "Multipart/", 10) == 0)
+ {
+ ptr3 = stristr(Line, "boundary");
+ if (ptr3)
+ {
+ ptr3+=9;
+
+ if ((*ptr3) == '"')
+ ptr3++;
+
+ strcpy(Boundary, ptr3);
+ ptr3 = strchr(Boundary, '"');
+ if (ptr3) *ptr3 = 0;
+ ptr3 = strchr(Boundary, 13); // CR
+ if (ptr3) *ptr3 = 0;
+ break;
+ }
+ else
+ return NULL; // Can't do anything without a boundary ??
+ }
+ }
+ ptr = ptr2;
+ ptr++;
+ }
+
+ // Find First part - there is a boundary before it
+
+ ptr = strstr(ptr2, Boundary);
+
+ // Next should be crlf then part
+
+ ptr = strstr(ptr, "\r\n");
+
+ if (ptr)
+ ptr += 2; // Over CRLF
+
+ *Input = ptr; // Return first part or NULL
+ return _strdup(Boundary);
+}
+
+BOOL unpackPart(char * Boundary, char ** Input, char ** Name, char ** Value, int * ValLen, char * End)
+{
+ // Format seems to be
+/*
+ ------WebKitFormBoundaryABJaEbBWB5SuAHmq
+ Content-Disposition: form-data; name="Subj"
+
+ subj
+ ------WebKitFormBoundaryABJaEbBWB5SuAHmq
+ Content-Disposition: form-data; name="myFile[]"; filename="exiftool.txt"
+ Content-Type: text/plain
+
+ c:\exiftool "-filenameSave Attachments ", Key, Msg->number);
+
+ WebMail->Files = 0;
+
+ ptr1 = MsgBytes;
+
+ // ptr += sprintf(ptr, "Message has Attachments\r\n\r\n");
+
+ while(*ptr1 != 13)
+ {
+ ptr2 = strchr(ptr1, 10); // Find CR
+
+ if (memcmp(ptr1, "Body: ", 6) == 0)
+ {
+ BodyLen = atoi(&ptr1[6]);
+ }
+
+ if (memcmp(ptr1, "File: ", 6) == 0)
+ {
+ char * ptr3 = strchr(&ptr1[6], ' '); // Find Space
+ *(ptr2 - 1) = 0;
+
+ WebMail->FileLen[WebMail->Files] = atoi(&ptr1[6]);
+ WebMail->FileName[WebMail->Files++] = _strdup(&ptr3[1]);
+ *(ptr2 - 1) = ' '; // put space back
+ }
+
+ ptr1 = ptr2;
+ ptr1++;
+ }
+
+ ptr1 += 2; // Over Blank Line and Separator
+
+ // ptr1 is pointing to body. Save for possible reply
+
+ WebMail->Body = malloc(BodyLen + 2);
+ memcpy(WebMail->Body, ptr1, BodyLen);
+ WebMail->Body[BodyLen] = 0;
+
+ *(ptr1 + BodyLen) = 0;
+
+ ptr += sprintf(ptr, "%s", MsgBytes); // B2 Header and Body
+
+ ptr1 += BodyLen + 2; // to first file
+
+ // Save pointers to file
+
+ attptr = ptr1;
+
+ for (i = 0; i < WebMail->Files; i++)
+ {
+ WebMail->FileBody[i] = malloc(WebMail->FileLen[i]);
+ memcpy(WebMail->FileBody[i], attptr, WebMail->FileLen[i]);
+ attptr += (WebMail->FileLen[i] + 2);
+ }
+
+ // if first (only??) attachment is XML and filename
+ // starts "RMS_Express_Form" process as HTML Form
+
+ if (DisplayHTML && _memicmp(ptr1, "FileName[0], "RMS_Express_Form_", 16) == 0)
+ {
+ int Len = DisplayWebForm(Session, Msg, WebMail->FileName[0], ptr1, Reply, MsgBytes, BodyLen + 32); // 32 for added "has attachments"
+ free(MsgBytes);
+
+ // Flag as read
+
+ if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
+ {
+ if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
+ {
+ if (Msg->status != 'Y')
+ {
+ Msg->status = 'Y';
+ Msg->datechanged=time(NULL);
+ SaveMessageDatabase();
+ SendMessageReadEvent(Session->Callsign, Msg);
+ }
+ }
+ }
+
+ return Len;
+ }
+
+ for (i = 0; i < WebMail->Files; i++)
+ {
+ int n;
+ char * p = ptr1;
+ char c;
+
+ // Check if message is probably binary
+
+ int BinCount = 0;
+
+ NewLen = WebMail->FileLen[i];
+
+ for (n = 0; n < NewLen; n++)
+ {
+ c = *p;
+
+ if (c==0 || (c & 128))
+ BinCount++;
+
+ p++;
+
+ }
+
+ if (BinCount > NewLen/10)
+ {
+ // File is probably Binary
+
+ ptr += sprintf(ptr, "\rAttachment %s is a binary file\r", WebMail->FileName[i]);
+ }
+ else
+ {
+ *(ptr1 + NewLen) = 0;
+ ptr += sprintf(ptr, "\rAttachment %s\r\r", WebMail->FileName[i]);
+ RemoveLF(ptr1, NewLen + 1); // Removes LF after CR but not on its own
+
+ ptr += sprintf(ptr, "%s\r\r", ptr1);
+
+ User->Total.MsgsSent[Index] ++;
+ User->Total.BytesForwardedOut[Index] += NewLen;
+ }
+
+ ptr1 += WebMail->FileLen[i];
+ ptr1 +=2; // Over separator
+ }
+
+ free(Save);
+
+ ptr += sprintf(ptr, "\r\r[End of Message #%d from %s]\r", Number, Msg->from);
+
+ RemoveLF(Message, (int)strlen(Message) + 1); // Removes LF after CR but not on its own
+
+ if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
+ {
+ if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
+ {
+ if (Msg->status != 'Y')
+ {
+ Msg->status = 'Y';
+ Msg->datechanged=time(NULL);
+ SaveMessageDatabase();
+ SendMessageReadEvent(Session->Callsign, Msg);
+ }
+ }
+ }
+
+ if (DisplayHTML && stristr(Message, ""))
+ DisplayStyle = "div"; // Use div so HTML and XML are interpreted
+
+ return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, DisplayStyle, Message, DisplayStyle);
+ }
+
+ // Remove B2 Headers (up to the File: Line)
+
+ // ptr1 = strstr(MsgBytes, "Body:");
+
+ // if (ptr1)
+ // MsgBytes = ptr1;
+ }
+
+ // Body may have cr cr lf which causes double space
+
+ crcrptr = strstr(MsgBytes, "\r\r\n");
+
+ while (crcrptr)
+ {
+ *crcrptr = ' ';
+ crcrptr = strstr(crcrptr, "\r\r\n");
+ }
+
+ // Remove lf chars
+
+ msgLen = RemoveLF(MsgBytes, msgLen);
+
+ User->Total.MsgsSent[Index] ++;
+ // User->Total.BytesForwardedOut[Index] += Length;
+
+ // if body not UTF-8, convert it
+
+ if (WebIsUTF8(MsgBytes, msgLen) == FALSE)
+ {
+ int code = TrytoGuessCode(MsgBytes, msgLen);
+
+ UCHAR * UTF = malloc(msgLen * 3);
+
+ if (code == 437)
+ msgLen = Convert437toUTF8(MsgBytes, msgLen, UTF);
+ else if (code == 1251)
+ msgLen = Convert1251toUTF8(MsgBytes, msgLen, UTF);
+ else
+ msgLen = Convert1252toUTF8(MsgBytes, msgLen, UTF);
+
+ free(MsgBytes);
+ Save = MsgBytes = UTF;
+
+ MsgBytes[msgLen] = 0;
+ }
+
+ // ptr += sprintf(ptr, "%s", MsgBytes);
+
+ memcpy(ptr, MsgBytes, msgLen);
+ ptr += msgLen;
+ ptr[0] = 0;
+
+ free(Save);
+
+ ptr += sprintf(ptr, "\r\r[End of Message #%d from %s]\r", Number, Msg->from);
+
+ if ((_stricmp(Msg->to, User->Call) == 0) || ((User->flags & F_SYSOP) && (_stricmp(Msg->to, "SYSOP") == 0)))
+ {
+ if ((Msg->status != 'K') && (Msg->status != 'H') && (Msg->status != 'F') && (Msg->status != 'D'))
+ {
+ if (Msg->status != 'Y')
+ {
+ Msg->status = 'Y';
+ Msg->datechanged=time(NULL);
+ SaveMessageDatabase();
+ SendMessageReadEvent(Session->Callsign, Msg);
+ }
+ }
+ }
+ }
+ else
+ {
+ ptr += sprintf(ptr, "File for Message %d not found\r", Number);
+ }
+
+ if (DisplayHTML && stristr(Message, ""))
+ DisplayStyle = "div"; // Use div so HTML and XML are interpreted
+
+
+ return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, DisplayStyle, Message, DisplayStyle);
+}
+
+int KillWebMailMessage(char * Reply, char * Key, struct UserInfo * User, int Number)
+{
+ struct MsgInfo * Msg;
+ char Message[100] = "";
+
+ Msg = GetMsgFromNumber(Number);
+
+ if (Msg == NULL)
+ {
+ sprintf(Message, "Message %d not found", Number);
+ goto returnit;
+ }
+
+ if (OkToKillMessage(User->flags & F_SYSOP, User->Call, Msg))
+ {
+ FlagAsKilled(Msg, TRUE);
+ sprintf(Message, "Message #%d Killed\r", Number);
+ goto returnit;
+ }
+
+ sprintf(Message, "Not your message\r");
+
+returnit:
+ return sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, "", Key, Key, Key, "div", Message, "div");
+}
+
+void freeKeys(KeyValues * Keys)
+{
+ while (Keys->Key)
+ {
+ free(Keys->Key);
+ free(Keys->Value);
+ Keys++;
+ }
+}
+
+void FreeWebMailFields(WebMailInfo * WebMail)
+{
+ // release any malloc'ed resources
+
+ int i;
+ char * SaveReply;
+ int * SaveRlen;
+
+ if (WebMail == NULL)
+ return;
+
+ if (WebMail->txtFile)
+ free(WebMail->txtFile);
+
+ if (WebMail->txtFileName)
+ free(WebMail->txtFileName);
+
+ if (WebMail->InputHTMLName)
+ free(WebMail->InputHTMLName);
+
+ if (WebMail->DisplayHTMLName)
+ free(WebMail->DisplayHTMLName);
+
+ if (WebMail->ReplyHTMLName)
+ free(WebMail->ReplyHTMLName);
+
+ if (WebMail->To)
+ free(WebMail->To);
+ if (WebMail->CC)
+ free(WebMail->CC);
+ if (WebMail->Subject)
+ free(WebMail->Subject);
+ if (WebMail->BID)
+ free(WebMail->BID);
+ if (WebMail->Body)
+ free(WebMail->Body);
+ if (WebMail->XML)
+ free(WebMail->XML);
+ if (WebMail->XMLName)
+ free(WebMail->XMLName);
+
+ if (WebMail->OrigTo)
+ free(WebMail->OrigTo);
+ if (WebMail->OrigSubject)
+ free(WebMail->OrigSubject);
+ if (WebMail->OrigBID)
+ free(WebMail->OrigBID);
+ if (WebMail->OrigBody)
+ free(WebMail->OrigBody);
+
+ freeKeys(WebMail->txtKeys);
+ freeKeys(WebMail->XMLKeys);
+
+ for (i = 0; i < WebMail->Files; i++)
+ {
+ free(WebMail->FileBody[i]);
+ free(WebMail->FileName[i]);
+ }
+
+ if (WebMail->Header)
+ free(WebMail->Header);
+ if (WebMail->Footer)
+ free(WebMail->Footer);
+
+ SaveReply = WebMail->Reply;
+ SaveRlen = WebMail->RLen;
+
+#ifndef WIN32
+ if (WebMail->iconv_toUTF8)
+ iconv_close(WebMail->iconv_toUTF8);
+#endif
+
+ memset(WebMail, 0, sizeof(WebMailInfo));
+
+ WebMail->Reply = SaveReply;
+ WebMail->RLen = SaveRlen;
+
+ return;
+}
+
+
+void ProcessWebMailMessage(struct HTTPConnectionInfo * Session, char * Key, BOOL LOCAL, char * Method, char * NodeURL, char * input, char * Reply, int * RLen, int InputLen)
+{
+ char * URLParams = strlop(Key, '&');
+ int ReplyLen;
+ char Appl = 'M';
+
+ // Webmail doesn't use the normal Mail Key.
+
+ // webscript.js doesn't need a key
+
+ if (_stricmp(NodeURL, "/WebMail/webscript.js") == 0)
+ {
+ if (jsTemplate)
+ free(jsTemplate);
+
+ jsTemplate = GetTemplateFromFile(2, "webscript.js");
+
+ ReplyLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
+ "Cache-Control: max-age=60\r\nContent-Type: text/javascript\r\n\r\n%s", (int)strlen(jsTemplate), jsTemplate);
+ *RLen = ReplyLen;
+ return;
+ }
+
+ // Neither do js or file downloads
+
+ // This could be a request for a Template file
+ // WebMail/Local_Templates/My Forms/inc/logo_ad63.png
+ // WebMail/Standard Templates/
+
+
+ if (_memicmp(NodeURL, "/WebMail/Local", 14) == 0 || (_memicmp(NodeURL, "/WebMail/Standard", 17) == 0))
+ {
+ int FileSize;
+ char * MsgBytes;
+ char MsgFile[512];
+ FILE * hFile;
+ size_t ReadLen;
+ char TimeString[64];
+ char FileTimeString[64];
+ struct stat STAT;
+ char * FN = &NodeURL[9];
+ char * fileBit = FN;
+ char * ext;
+ char Type[64] = "Content-Type: text/html\r\n";
+
+ UndoTransparency(FN);
+ ext = strchr(FN, '.');
+
+ sprintf(MsgFile, "%s/%s", BPQDirectory, FN);
+
+ while (strchr(fileBit, '/'))
+ fileBit = strlop(fileBit, '/');
+
+ if (stat(MsgFile, &STAT) == -1)
+ {
+ *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
+ return;
+ }
+
+ hFile = fopen(MsgFile, "rb");
+
+ if (hFile == 0)
+ {
+ *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
+ return;
+ }
+
+ FileSize = STAT.st_size;
+ MsgBytes = malloc(FileSize + 1);
+ ReadLen = fread(MsgBytes, 1, FileSize, hFile);
+
+ fclose(hFile);
+
+ FormatTime2(FileTimeString, STAT.st_ctime);
+ FormatTime2(TimeString, time(NULL));
+
+ ext++;
+
+ if (_stricmp(ext, "js") == 0)
+ strcpy(Type, "Content-Type: text/javascript\r\n");
+
+ if (_stricmp(ext, "css") == 0)
+ strcpy(Type, "Content-Type: text/css\r\n");
+
+ if (_stricmp(ext, "pdf") == 0)
+ strcpy(Type, "Content-Type: application/pdf\r\n");
+
+ if (_stricmp(ext, "jpg") == 0 || _stricmp(ext, "jpeg") == 0 || _stricmp(ext, "png") == 0 ||
+ _stricmp(ext, "gif") == 0 || _stricmp(ext, "bmp") == 0 || _stricmp(ext, "ico") == 0)
+ strcpy(Type, "Content-Type: image\r\n");
+
+ // File may be binary so output header then copy in message
+
+ *RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
+ "%s"
+ "Date: %s\r\n"
+ "Last-Modified: %s\r\n"
+ "\r\n", FileSize, Type,TimeString, FileTimeString);
+
+ memcpy(&Reply[*RLen], MsgBytes, FileSize);
+ *RLen += FileSize;
+ free (MsgBytes);
+ return;
+ }
+
+ //
+
+ if (_memicmp(NodeURL, "/WebMail/WMFile/", 16) == 0)
+ {
+ int FileSize;
+ char * MsgBytes;
+ char MsgFile[512];
+ FILE * hFile;
+ size_t ReadLen;
+ char TimeString[64];
+ char FileTimeString[64];
+ struct stat STAT;
+ char * FN = &NodeURL[16];
+ char * fileBit = FN;
+ char * ext;
+ char Type[64] = "Content-Type: text/html\r\n";
+
+
+ UndoTransparency(FN);
+ ext = strchr(FN, '.');
+
+ sprintf(MsgFile, "%s/%s", BPQDirectory, FN);
+
+ while (strchr(fileBit, '/'))
+ fileBit = strlop(fileBit, '/');
+
+ if (stat(MsgFile, &STAT) == -1)
+ {
+ *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
+ return;
+ }
+
+ hFile = fopen(MsgFile, "rb");
+
+ if (hFile == 0)
+ {
+ *RLen = sprintf(Reply, "HTTP/1.1 404 Not Found\r\nContent-Length: 16\r\n\r\nPage not found\r\n");
+ return;
+ }
+
+ FileSize = STAT.st_size;
+ MsgBytes = malloc(FileSize + 1);
+ ReadLen = fread(MsgBytes, 1, FileSize, hFile);
+
+ fclose(hFile);
+
+ FormatTime2(FileTimeString, STAT.st_ctime);
+ FormatTime2(TimeString, time(NULL));
+
+ ext++;
+
+ if (_stricmp(ext, "js") == 0)
+ strcpy(Type, "Content-Type: text/javascript\r\n");
+
+ if (_stricmp(ext, "css") == 0)
+ strcpy(Type, "Content-Type: text/css\r\n");
+
+ if (_stricmp(ext, "pdf") == 0)
+ strcpy(Type, "Content-Type: application/pdf\r\n");
+
+ if (_stricmp(ext, "jpg") == 0 || _stricmp(ext, "jpeg") == 0 || _stricmp(ext, "png") == 0 ||
+ _stricmp(ext, "gif") == 0 || _stricmp(ext, "bmp") == 0 || _stricmp(ext, "ico") == 0)
+ strcpy(Type, "Content-Type: image\r\n");
+
+ // File may be binary so output header then copy in message
+
+ *RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
+ "%s"
+ "Date: %s\r\n"
+ "Last-Modified: %s\r\n"
+ "\r\n", FileSize, Type,TimeString, FileTimeString);
+
+ memcpy(&Reply[*RLen], MsgBytes, FileSize);
+ *RLen += FileSize;
+ free (MsgBytes);
+ return;
+ }
+
+ Session = NULL;
+
+ if (Key && Key[0])
+ Session = FindWMSession(Key);
+
+ if (Session == NULL)
+ {
+ // Lost Session
+
+ if (LOCAL)
+ {
+ Session = AllocateWebMailSession();
+
+ Key = Session->Key;
+
+ if (SYSOPCall[0])
+ Session->User = LookupCall(SYSOPCall);
+ else
+ Session->User = LookupCall(BBSName);
+
+ if (Session->User)
+ {
+ strcpy(NodeURL, "/WebMail/WebMail");
+ Session->WebMailSkip = 0;
+ Session->WebMailLastUsed = time(NULL);
+ }
+ }
+ else
+ {
+ // Send Login Page unless Signon request
+
+ if (_stricmp(NodeURL, "/WebMail/Signon") != 0 || strcmp(Method, "POST") != 0)
+ {
+ ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+ return;
+ }
+ }
+ }
+
+ if (strcmp(Method, "POST") == 0)
+ {
+ if (_stricmp(NodeURL, "/WebMail/Signon") == 0)
+ {
+ char * msg = strstr(input, "\r\n\r\n"); // End of headers
+ char * user, * password, * Key;
+ char Msg[128];
+ int n;
+
+ if (msg)
+ {
+ struct UserInfo * User;
+
+ if (strstr(msg, "Cancel=Cancel"))
+ {
+ *RLen = sprintf(Reply, "");
+ return;
+ }
+ // Webmail Gets Here with a dummy Session
+
+ Session = AllocateWebMailSession();
+ Session->WebMail->Reply = Reply;
+ Session->WebMail->RLen = RLen;
+
+
+ Key = Session->Key;
+
+ user = strtok_s(&msg[9], "&", &Key);
+ password = strtok_s(NULL, "=", &Key);
+ password = Key;
+
+ Session->User = User = LookupCall(user);
+
+ if (User)
+ {
+ // Check Password
+
+ if (password[0] && strcmp(User->pass, password) == 0)
+ {
+ // send Message Index
+
+ Session->WebMailLastUsed = time(NULL);
+ Session->WebMailSkip = 0;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+ Session->WebMailMine = FALSE;
+
+ if (WebMailTemplate)
+ {
+ free(WebMailTemplate);
+ WebMailTemplate = NULL;
+ }
+
+ if (User->flags & F_Excluded)
+ {
+ n = sprintf_s(Msg, sizeof(Msg), "Webmail Connect from %s Rejected by Exclude Flag", _strupr(user));
+ WriteLogLine(NULL, '|',Msg, n, LOG_BBS);
+ ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+ return;
+ }
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ n=sprintf_s(Msg, sizeof(Msg), "Webmail Connect from %s", _strupr(user));
+ WriteLogLine(NULL, '|',Msg, n, LOG_BBS);
+
+ return;
+ }
+
+ }
+
+ // Bad User or Pass
+
+ ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+ return;
+ }
+ }
+
+ Session->WebMail->Reply = Reply;
+ Session->WebMail->RLen = RLen;
+
+ if (_stricmp(NodeURL, "/WebMail/EMSave") == 0)
+ {
+ // Save New Message
+
+ SaveNewMessage(Session, input, Reply, RLen, Key, InputLen);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/Submit") == 0)
+ {
+ // Get the POST data from the page and place in message
+
+ char * param = strstr(input, "\r\n\r\n"); // End of headers
+ WebMailInfo * WebMail = Session->WebMail;
+
+ if (WebMail == NULL)
+ return; // Can't proceed if we have no info on form
+
+ ProcessFormInput(Session, input, Reply, RLen, InputLen);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/FormMsgSave") == 0)
+ {
+ // Save New Message
+
+ SaveTemplateMessage(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/GetTemplates") == 0)
+ {
+ SendTemplateSelectScreen(Session, input, InputLen);
+ return;
+ }
+
+ // End of POST section
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMLogout") == 0)
+ {
+ Session->Key[0] = 0;
+ Session->WebMailLastUsed = 0;
+ ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+ return;
+ }
+
+ if ((_stricmp(NodeURL, "/WebMail/MailEntry") == 0) ||
+ (_stricmp(NodeURL, "/WebMail") == 0) ||
+ (_stricmp(NodeURL, "/WebMail/") == 0))
+ {
+ // Entry from Menu if signed in, continue. If not and Localhost
+ // signin as sysop.
+
+ if (Session->User == NULL)
+ {
+ // Not yet signed in
+
+ if (LOCAL)
+ {
+ // Webmail Gets Here with a dummy Session
+
+ Session = AllocateWebMailSession();
+ Session->WebMail->Reply = Reply;
+ Session->WebMail->RLen = RLen;
+
+ Key = Session->Key;
+
+ if (SYSOPCall[0])
+ Session->User = LookupCall(SYSOPCall);
+ else
+ Session->User = LookupCall(BBSName);
+
+ if (Session->User)
+ {
+ strcpy(NodeURL, "/WebMail/WebMail");
+ Session->WebMailSkip = 0;
+ Session->WebMailLastUsed = time(NULL);
+ }
+ }
+ else
+ {
+ // Send Login Page
+
+ ReplyLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+ return;
+ }
+ }
+ }
+
+ Session->WebMail->Reply = Reply;
+ Session->WebMail->RLen = RLen;
+
+ if (_stricmp(NodeURL, "/WebMail/WebMail") == 0)
+ {
+ if (WebMailTemplate)
+ {
+ free(WebMailTemplate);
+ WebMailTemplate = NULL;
+ }
+
+ Session->WebMailSkip = 0;
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMAll") == 0)
+ {
+ Session->WebMailSkip = 0;
+ Session->WebMailTypes[0] = 0;
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMB") == 0)
+ {
+ Session->WebMailSkip = 0;
+ strcpy(Session->WebMailTypes, "B");
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMP") == 0)
+ {
+ Session->WebMailSkip = 0;
+ strcpy(Session->WebMailTypes, "P");
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMT") == 0)
+ {
+ Session->WebMailSkip = 0;
+ strcpy(Session->WebMailTypes, "T");
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMMine") == 0)
+ {
+ Session->WebMailSkip = 0;
+ Session->WebMailTypes[0] = 0;
+ Session->WebMailMine = TRUE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMtoMe") == 0)
+ {
+ Session->WebMailSkip = 0;
+ Session->WebMailTypes[0] = 0;
+ Session->WebMailMine = FALSE;
+ Session->WebMailMyTX = FALSE;
+ Session->WebMailMyRX = TRUE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMfromMe") == 0)
+ {
+ Session->WebMailSkip = 0;
+ Session->WebMailTypes[0] = 0;
+ Session->WebMailMine = TRUE;
+ Session->WebMailMyTX = TRUE;
+ Session->WebMailMyRX = FALSE;
+
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+
+ if (_stricmp(NodeURL, "/WebMail/WMSame") == 0)
+ {
+ *RLen = SendWebMailHeader(Reply, Session->Key, Session);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/WebMail/WMAuto") == 0)
+ {
+ // Auto Refresh Version of index page. Uses Web Sockets
+
+ char Page[4096];
+
+ char WebSockPage[] =
+ "\r\n"
+ " \r\n"
+ " \r\n"
+ " \r\n"
+ " \r\n"
+ "\r\n"
+ "\r\n"
+
+ "\r\n"
+ " %s Webmail Interface - User %s - Message List
\r\n"
+ "
\r\n"
+ "\r\n"
+ "\r\n"
+ " Bulls \r\n"
+ "Personal \r\n"
+ "NTS \r\n"
+ "All Types \r\n"
+ "Mine \r\n"
+ "My Sent \r\n"
+ "My Rxed \r\n"
+ "Auto Refresh \r\n"
+ "Send Message \r\n"
+ "Logout \r\n"
+ "Node Menu
\r\n"
+
+ "
"
+ "
| Reply | " + "Kill Message | " + "Display as Text | " + "Next | " + "Previous | " + "Back to List | " + "