+#endif
+
+extern char NodeTail[];
+extern char BBSName[10];
+
+extern char LTFROMString[2048];
+extern char LTTOString[2048];
+extern char LTATString[2048];
+
+//static UCHAR BPQDirectory[260];
+
+extern ConnectionInfo Connections[];
+extern int NumberofStreams;
+extern time_t MaintClock; // Time to run housekeeping
+
+extern int SMTPMsgs;
+
+extern int ChatApplNum;
+extern int MaxChatStreams;
+
+extern char Position[81];
+extern char PopupText[251];
+extern int PopupMode;
+extern int reportMailEvents;
+
+#define MaxCMS 10 // Numbr of addresses we can keep - currently 4 are used.
+
+struct UserInfo * BBSLIST[NBBBS + 1];
+
+int MaxBBS = 0;
+
+#define MAIL
+#include "httpconnectioninfo.h"
+
+struct TCPINFO * TCP;
+
+VOID ProcessMailSignon(struct TCPINFO * TCP, char * MsgPtr, char * Appl, char * Reply, int * RLen);
+static struct HTTPConnectionInfo * FindSession(char * Key);
+VOID ProcessUserUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID ProcessMsgFwdUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key);
+VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID ProcessUIUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID SendUserSelectPage(char * Reply, int * ReplyLen, char * Key);
+VOID SendFWDSelectPage(char * Reply, int * ReplyLen, char * Key);
+int EncryptPass(char * Pass, char * Encrypt);
+VOID ProcessFWDUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID SendStatusPage(char * Reply, int * ReplyLen, char * Key);
+VOID SendUIPage(char * Reply, int * ReplyLen, char * Key);
+VOID GetParam(char * input, char * key, char * value);
+BOOL GetConfig(char * ConfigName);
+VOID ProcessDisUser(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+int APIENTRY SessionControl(int stream, int command, int param);
+int SendMessageDetails(struct MsgInfo * Msg, char * Reply, char * Key);
+VOID ProcessMsgUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID ProcessMsgAction(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+int APIENTRY GetNumberofPorts();
+int APIENTRY GetPortNumber(int portslot);
+UCHAR * APIENTRY GetPortDescription(int portslot, char * Desc);
+struct PORTCONTROL * APIENTRY GetPortTableEntryFromSlot(int portslot);
+VOID SendHouseKeeping(char * Reply, int * ReplyLen, char * Key);
+VOID SendWelcomePage(char * Reply, int * ReplyLen, char * Key);
+VOID SaveWelcome(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key);
+VOID GetMallocedParam(char * input, char * key, char ** value);
+VOID SaveMessageText(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID SaveHousekeeping(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key);
+VOID SaveWP(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key);
+int SendWPDetails(WPRec * WP, char * Reply, char * Key);
+int SendUserDetails(struct HTTPConnectionInfo * Session, char * Reply, char * Key);
+int SetupNodeMenu(char * Buff);
+VOID SendFwdSelectPage(char * Reply, int * ReplyLen, char * Key);
+VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char * Key);
+VOID SetMultiStringValue(char ** values, char * Multi);
+VOID SendFwdMainPage(char * Reply, int * ReplyLen, char * Key);
+VOID SaveFwdCommon(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+VOID SaveFwdDetails(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
+char ** SeparateMultiString(char * MultiString, BOOL NoToUpper);
+VOID TidyPrompts();
+char * GetTemplateFromFile(int Version, char * FN);
+VOID FormatTime(char * Time, time_t cTime);
+struct MsgInfo * GetMsgFromNumber(int msgno);
+BOOL CheckUserMsg(struct MsgInfo * Msg, char * Call, BOOL SYSOP);
+BOOL OkToKillMessage(BOOL SYSOP, char * Call, struct MsgInfo * Msg);
+int MulticastStatusHTML(char * Reply);
+void ProcessWebMailMessage(struct HTTPConnectionInfo * Session, char * Key, BOOL LOCAL, char * Method, char * NodeURL, char * input, char * Reply, int * RLen, int InputLen);
+int SendWebMailHeader(char * Reply, char * Key, struct HTTPConnectionInfo * Session);
+struct UserInfo * FindBBS(char * Name);
+void ReleaseWebMailStruct(WebMailInfo * WebMail);
+VOID TidyWelcomeMsg(char ** pPrompt);
+
+char UNC[] = "";
+char CHKD[] = "checked=checked ";
+char sel[] = "selected";
+
+char Sent[] = "#98FFA0";
+char ToSend[] = "#FFFF00";
+char NotThisOne[] = "#FFFFFF";
+
+static char PassError[] = "Sorry, User or Password is invalid - please try again
";
+
+static char BusyError[] = "Sorry, No sessions available - please try later
";
+
+extern char WebMailSignon[];
+
+char MailSignon[] = "BPQ32 Mail Server Access"
+ "BPQ32 Mail Server %s Access
"
+ "Please enter Callsign and Password to access the BBS
"
+ "";
+
+
+char MailPage[] = "%s's BBS Web Server"
+ ""
+ ""
+ "BPQ32 BBS %s
"
+ "
";
+
+char RefreshMainPage[] = ""
+ ""
+ ""
+ "%s's BBS Web Server"
+ "BPQ32 BBS %s
"
+ "
";
+
+char StatusPage [] =
+
+"";
+
+
+char UIHddr [] = "";
+
+char FWDSelectHddr[] =
+ "";
+
+char UserSelectHddr[] =
+ "";
+
+char UserUpdateHddr[] =
+ "Update User %s
"
+ "
";
+
+static char MailDetailPage[] =
+""
+"MsgEditMessage %d
"
+"";
+
+char Welcome[] = "";
+
+static char MsgEditPage[] = ""
+""
+"";
+
+static char WPDetail[] = "";
+
+
+static char LostSession[] = ""
+"";
+
+
+char * MsgEditTemplate = NULL;
+char * HousekeepingTemplate = NULL;
+char * ConfigTemplate = NULL;
+char * WPTemplate = NULL;
+char * UserListTemplate = NULL;
+char * UserDetailTemplate = NULL;
+char * FwdTemplate = NULL;
+char * FwdDetailTemplate = NULL;
+char * WebMailTemplate = NULL;
+char * WebMailMsgTemplate = NULL;
+char * jsTemplate = NULL;
+
+
+#ifdef LINBPQ
+UCHAR * GetBPQDirectory();
+#endif
+
+static int compare(const void *arg1, const void *arg2)
+{
+ // Compare Calls. Fortunately call is at start of stuct
+
+ return _stricmp(*(char**)arg1 , *(char**)arg2);
+}
+
+int SendHeader(char * Reply, char * Key)
+{
+ return sprintf(Reply, MailPage, BBSName, BBSName, Key, Key, Key, Key, Key, Key, Key, Key);
+}
+
+
+void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len)
+{
+ if (WebIsUTF8(Title, (int)strlen(Title)) == FALSE)
+ {
+ // With Windows it is simple - convert using current codepage
+ // I think the only reliable way is to convert to unicode and back
+
+ int origlen = (int)strlen(Title) + 1;
+#ifdef WIN32
+ WCHAR BufferW[128];
+ int wlen;
+ int len = origlen;
+
+ wlen = MultiByteToWideChar(CP_ACP, 0, Title, len, BufferW, origlen * 2);
+ len = WideCharToMultiByte(CP_UTF8, 0, BufferW, wlen, UTF8Title, origlen * 2, NULL, NULL);
+#else
+ size_t left = Len - 1;
+ size_t len = origlen;
+
+ iconv_t * icu = WebMail->iconv_toUTF8;
+
+ if (WebMail->iconv_toUTF8 == NULL)
+ icu = WebMail->iconv_toUTF8 = iconv_open("UTF-8//IGNORE", "CP1252");
+
+ if (icu == (iconv_t)-1)
+ {
+ strcpy(UTF8Title, Title);
+ WebMail->iconv_toUTF8 = NULL;
+ return;
+ }
+
+ char * orig = UTF8Title;
+
+ iconv(icu, NULL, NULL, NULL, NULL); // Reset State Machine
+ iconv(icu, &Title, &len, (char ** __restrict__)&UTF8Title, &left);
+
+#endif
+ }
+ else
+ strcpy(UTF8Title, Title);
+}
+
+BOOL GotFirstMessage = 0;
+
+void ProcessMailHTTPMessage(struct HTTPConnectionInfo * Session, char * Method, char * URL, char * input, char * Reply, int * RLen, int InputLen)
+{
+ char * Context = 0, * NodeURL;
+ int ReplyLen;
+ BOOL LOCAL = FALSE;
+ char * Key;
+ char Appl = 'M';
+
+ if (URL[0] == 0 || Method == NULL)
+ return;
+
+ if (strstr(input, "Host: 127.0.0.1"))
+ LOCAL = TRUE;
+
+ if (Session->TNC == (void *)1) // Re-using an address as a flag
+ LOCAL = TRUE;
+
+ NodeURL = strtok_s(URL, "?", &Context);
+
+ Key = Session->Key;
+
+ if (_memicmp(URL, "/WebMail", 8) == 0)
+ {
+ // Pass All Webmail messages to Webmail
+
+ ProcessWebMailMessage(Session, Context, LOCAL, Method, NodeURL, input, Reply, RLen, InputLen);
+ return;
+
+ }
+
+ // There is a problem if Mail is reloaded without reloading the node
+
+ if (GotFirstMessage == 0)
+ {
+ if (_stricmp(NodeURL, "/Mail/Header") == 0 || _stricmp(NodeURL, "/Mail/Lost") == 0)
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ }
+ else
+ {
+ *RLen = sprintf(Reply, "", Session->Key);
+ }
+
+ GotFirstMessage = 1;
+ return;
+ }
+
+ if (_memicmp(URL, "/Mail/API/", 10) == 0)
+ {
+ *RLen = APIProcessHTTPMessage(Reply, Method, URL, input, LOCAL, 0);
+ return;
+ }
+
+
+ if (strcmp(Method, "POST") == 0)
+ {
+ if (_stricmp(NodeURL, "/Mail/Header") == 0)
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+
+ if (_stricmp(NodeURL, "/Mail/Config") == 0)
+ {
+ NodeURL[strlen(NodeURL)] = ' '; // Undo strtok
+ ProcessConfUpdate(Session, input, Reply, RLen, Key);
+ return ;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/UI") == 0)
+ {
+ NodeURL[strlen(NodeURL)] = ' '; // Undo strtok
+ ProcessUIUpdate(Session, input, Reply, RLen, Key);
+ return ;
+ }
+ if (_stricmp(NodeURL, "/Mail/FwdCommon") == 0)
+ {
+ SaveFwdCommon(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/DisSession") == 0)
+ {
+ ProcessDisUser(Session, input, Reply, RLen, Key);
+ return ;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/UserDetails") == 0)
+ {
+ char * param = strstr(input, "\r\n\r\n"); // End of headers
+
+ if (param)
+ {
+ Session->User = LookupCall(param+4);
+ if (Session->User)
+ {
+ * RLen = SendUserDetails(Session, Reply, Key);
+ return;
+ }
+ }
+ }
+
+
+ if (_stricmp(NodeURL, "/Mail/UserSave") == 0)
+ {
+ ProcessUserUpdate(Session, input, Reply, RLen, Key);
+ return ;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/MsgDetails") == 0)
+ {
+ char * param = strstr(input, "\r\n\r\n"); // End of headers
+
+ if (param)
+ {
+ int Msgno = atoi(param + 4);
+ struct MsgInfo * Msg = FindMessageByNumber(Msgno);
+
+ Session->Msg = Msg; // Save current Message
+
+ * RLen = SendMessageDetails(Msg, Reply, Key);
+ return;
+ }
+ }
+
+ if (_stricmp(NodeURL, "/Mail/MsgSave") == 0)
+ {
+ ProcessMsgUpdate(Session, input, Reply, RLen, Key);
+ return ;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/EMSave") == 0)
+ {
+ // Save Message Text
+
+ SaveMessageText(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/MsgAction") == 0)
+ {
+ ProcessMsgAction(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/MsgFwdUpdate") == 0)
+ {
+ ProcessMsgFwdUpdate(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/Welcome") == 0)
+ {
+ SaveWelcome(Session, input, Reply, RLen, Key);
+ return;
+ }
+ if (_stricmp(NodeURL, "/Mail/HK") == 0)
+ {
+ SaveHousekeeping(Session, input, Reply, RLen, Key);
+ return;
+ }
+ if (_stricmp(NodeURL, "/Mail/WPDetails") == 0)
+ {
+ char * param = strstr(input, "\r\n\r\n"); // End of headers
+
+ if (param)
+ {
+ WPRec * WP = LookupWP(param+4);
+ Session->WP = WP; // Save current Message
+
+ * RLen = SendWPDetails(WP, Reply, Key);
+ return;
+ }
+ }
+ if (_stricmp(NodeURL, "/Mail/WPSave") == 0)
+ {
+ SaveWP(Session, input, Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/MsgInfo.txt") == 0)
+ {
+ int n, len = 0;
+ char * FF = "", *FT = "", *FB = "", *FV = "";
+ char * param, * ptr1, *ptr2;
+ struct MsgInfo * Msg;
+ char UCto[80];
+ char UCfrom[80];
+ char UCvia[80];
+ char UCbid[80];
+
+ // Get filter string
+
+ param = strstr(input, "\r\n\r\n"); // End of headers
+
+
+ if (param)
+ {
+ ptr1 = param + 4;
+ ptr2 = strchr(ptr1, '|');
+ if (ptr2){*(ptr2++) = 0; FF = ptr1; ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FT = ptr1;ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FV = ptr1;ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0; FB = ptr1;ptr1 = ptr2;}
+ }
+
+ if (FT[0])
+ _strupr(FT);
+ if (FF[0])
+ _strupr(FF);
+ if (FV[0])
+ _strupr(FV);
+ if (FB[0])
+ _strupr(FB);
+
+ for (n = NumberofMessages; n >= 1; n--)
+ {
+ Msg = MsgHddrPtr[n];
+
+ strcpy(UCto, Msg->to);
+ strcpy(UCfrom, Msg->from);
+ strcpy(UCvia, Msg->via);
+ strcpy(UCbid, Msg->bid);
+
+ _strupr(UCto);
+ _strupr(UCfrom);
+ _strupr(UCvia);
+ _strupr(UCbid);
+
+ if ((!FT[0] || strstr(UCto, FT)) &&
+ (!FF[0] || strstr(UCfrom, FF)) &&
+ (!FB[0] || strstr(UCbid, FB)) &&
+ (!FV[0] || strstr(UCvia, FV)))
+ {
+ len += sprintf(&Reply[len], "%d|", Msg->number);
+ }
+ }
+ *RLen = len;
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/UserList.txt") == 0)
+ {
+ SendUserSelectPage(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/FwdList.txt") == 0)
+ {
+ SendFwdSelectPage(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/FwdDetails") == 0)
+ {
+ char * param;
+
+ param = strstr(input, "\r\n\r\n"); // End of headers
+
+ if (param)
+ {
+ Session->User = LookupCall(param+4);
+ if (Session->User)
+ {
+ SendFwdDetails(Session->User, Reply, RLen, Key);
+ return;
+ }
+ }
+ }
+
+ if (_stricmp(NodeURL, "/Mail/FWDSave") == 0)
+ {
+ SaveFwdDetails(Session, input, Reply, RLen, Key);
+ return ;
+ }
+
+ // End of POST section
+ }
+
+ if (strstr(NodeURL, "webscript.js"))
+ {
+ if (jsTemplate)
+ free(jsTemplate);
+
+ jsTemplate = GetTemplateFromFile(1, "webscript.js");
+
+ ReplyLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
+ "Cache-Control: max-age=900\r\nContent-Type: text/javascript\r\n\r\n%s", (int)strlen(jsTemplate), jsTemplate);
+ *RLen = ReplyLen;
+ return;
+ }
+
+
+ if (_stricmp(NodeURL, "/Mail/Header") == 0)
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/all.html") == 0)
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/Status") == 0 ||
+ _stricmp(NodeURL, "/Mail/DisSession") == 0) // Sent as POST by refresh timer for some reason
+ {
+ SendStatusPage(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/Conf") == 0)
+ {
+ if (ConfigTemplate)
+ free(ConfigTemplate);
+
+ ConfigTemplate = GetTemplateFromFile(7, "MainConfig.txt");
+
+ SendConfigPage(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/FWD") == 0)
+ {
+ if (FwdTemplate)
+ free(FwdTemplate);
+
+ FwdTemplate = GetTemplateFromFile(4, "FwdPage.txt");
+
+ if (FwdDetailTemplate)
+ free(FwdDetailTemplate);
+
+ FwdDetailTemplate = GetTemplateFromFile(3, "FwdDetail.txt");
+
+ SendFwdMainPage(Reply, RLen, Key);
+ return;
+ }
+ if (_stricmp(NodeURL, "/Mail/Wel") == 0)
+ {
+ SendWelcomePage(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/Users") == 0)
+ {
+ if (UserListTemplate)
+ free(UserListTemplate);
+
+ UserListTemplate = GetTemplateFromFile(4, "UserPage.txt");
+
+ if (UserDetailTemplate)
+ free(UserDetailTemplate);
+
+ UserDetailTemplate = GetTemplateFromFile(4, "UserDetail.txt");
+
+ *RLen = sprintf(Reply, UserListTemplate, Key, Key, BBSName,
+ Key, Key, Key, Key, Key, Key, Key, Key);
+
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/SaveMessage") == 0)
+ {
+ struct MsgInfo * Msg = Session->Msg;
+ char * MailBuffer;
+
+ int Files = 0;
+ int BodyLen;
+ char * ptr;
+ int WriteLen=0;
+ char Hddr[1000];
+ char FullTo[100];
+
+ MailBuffer = ReadMessageFile(Msg->number);
+ BodyLen = Msg->length;
+
+ ptr = MailBuffer;
+
+ if (_stricmp(Msg->to, "RMS") == 0)
+ sprintf(FullTo, "RMS:%s", Msg->via);
+ else
+ if (Msg->to[0] == 0)
+ sprintf(FullTo, "smtp:%s", Msg->via);
+ else
+ strcpy(FullTo, Msg->to);
+
+ sprintf(Hddr, "From: %s%s\r\nTo: %s\r\nType/Status: %c%c\r\nDate/Time: %s\r\nBid: %s\r\nTitle: %s\r\n\r\n",
+ Msg->from, Msg->emailfrom, FullTo, Msg->type, Msg->status, FormatDateAndTime((time_t)Msg->datecreated, FALSE), Msg->bid, Msg->title);
+
+ if (Msg->B2Flags & B2Msg)
+ {
+ // Remove B2 Headers (up to the File: Line)
+
+ char * bptr;
+ bptr = strstr(ptr, "Body:");
+ if (bptr)
+ {
+ BodyLen = atoi(bptr + 5);
+ bptr = strstr(bptr, "\r\n\r\n");
+
+ if (bptr)
+ ptr = bptr+4;
+ }
+ }
+
+ ptr[BodyLen] = 0;
+
+ sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Disposition: attachment; filename=\"SavedMsg%05d.txt\" \r\n\r\n",
+ (int)(strlen(Hddr) + strlen(ptr)), Msg->number);
+ strcat(Reply, Hddr);
+ strcat(Reply, ptr);
+
+ *RLen = (int)strlen(Reply);
+
+ free(MailBuffer);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/SaveAttachment") == 0)
+ {
+ struct MsgInfo * Msg = Session->Msg;
+ char * MailBuffer;
+
+ int Files = 0, i;
+ int BodyLen;
+ char * ptr;
+ int WriteLen=0;
+ char FileName[100][MAX_PATH] = {""};
+ int FileLen[100];
+ char Noatt[] = "Message has no attachments";
+
+
+ MailBuffer = ReadMessageFile(Msg->number);
+ BodyLen = Msg->length;
+
+ if ((Msg->B2Flags & Attachments) == 0)
+ {
+ sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s",
+ (int)strlen(Noatt), Noatt);
+ *RLen = (int)strlen(Reply);
+
+ free(MailBuffer);
+ return;
+ }
+
+ ptr = MailBuffer;
+
+ while(ptr && *ptr != 13)
+ {
+ char * ptr2 = strchr(ptr, 10); // Find CR
+
+ if (memcmp(ptr, "Body: ", 6) == 0)
+ {
+ BodyLen = atoi(&ptr[6]);
+ }
+
+ if (memcmp(ptr, "File: ", 6) == 0)
+ {
+ char * ptr1 = strchr(&ptr[6], ' '); // Find Space
+
+ FileLen[Files] = atoi(&ptr[6]);
+
+ memcpy(FileName[Files++], &ptr1[1], (ptr2-ptr1 - 2));
+ }
+
+ ptr = ptr2;
+ ptr++;
+ }
+
+ ptr += 4; // Over Blank Line and Separator
+ ptr += BodyLen; // to first file
+
+ if (Files == 0)
+ {
+ sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n\r\n%s",
+ (int)strlen(Noatt), Noatt);
+ *RLen = (int)strlen(Reply);
+ free(MailBuffer);
+ return;
+ }
+
+ *RLen = 0;
+
+ // For now only handle first
+
+ i = 0;
+
+// for (i = 0; i < Files; i++)
+ {
+ int Len = sprintf(&Reply[*RLen], "HTTP/1.1 200 OK\r\nContent-Length: %d\r\nContent-Disposition: attachment; filename=\"%s\" \r\n\r\n",
+ FileLen[i], FileName[i]);
+
+ memcpy(&Reply[Len + *RLen], ptr, FileLen[i]);
+
+ *RLen += (Len + FileLen[i]);
+
+ ptr += FileLen[i];
+ ptr +=2; // Over separator - I don't think there should be one
+ }
+
+ free(MailBuffer);
+ return;
+ }
+
+
+ if (_stricmp(NodeURL, "/Mail/Msgs") == 0)
+ {
+ struct UserInfo * USER = NULL;
+ int PageLen;
+
+ if (MsgEditTemplate)
+ free(MsgEditTemplate);
+
+ MsgEditTemplate = GetTemplateFromFile(2, "MsgPage.txt");
+
+ // Refresh BBS No to BBS list
+
+ MaxBBS = 0;
+
+ for (USER = BBSChain; USER; USER = USER->BBSNext)
+ {
+ int n = USER->BBSNumber;
+ BBSLIST[n] = USER;
+ if (n > MaxBBS)
+ MaxBBS = n;
+ }
+
+ PageLen = 334 + (MaxBBS / 8) * 24;
+
+ if (MsgEditTemplate)
+ {
+ int len =sprintf(Reply, MsgEditTemplate, PageLen, PageLen, PageLen - 97, Key, Key, Key, Key, Key,
+ BBSName, Key, Key, Key, Key, Key, Key, Key, Key);
+ *RLen = len;
+ return;
+ }
+
+
+
+
+ }
+
+ if (_stricmp(NodeURL, "/Mail/EditM") == 0)
+ {
+ // Edit Message
+
+ char * MsgBytes;
+
+ MsgBytes = ReadMessageFile(Session->Msg->number);
+
+ // See if Multipart
+
+// if (Msg->B2Flags & Attachments)
+// EnableWindow(GetDlgItem(hDlg, IDC_SAVEATTACHMENTS), TRUE);
+
+ if (MsgBytes)
+ {
+ *RLen = sprintf(Reply, MsgEditPage, Key, MsgBytes);
+ free (MsgBytes);
+ }
+ else
+ *RLen = sprintf(Reply, MsgEditPage, Key, "Message Not Found");
+
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/HK") == 0)
+ {
+ if (HousekeepingTemplate)
+ free(HousekeepingTemplate);
+
+ HousekeepingTemplate = GetTemplateFromFile(2, "Housekeeping.txt");
+
+ SendHouseKeeping(Reply, RLen, Key);
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/WP") == 0)
+ {
+ if (WPTemplate)
+ free(WPTemplate);
+
+ WPTemplate = GetTemplateFromFile(1, "WP.txt");
+
+ if (WPTemplate)
+ {
+ int len =sprintf(Reply, WPTemplate, Key, Key, Key, Key,
+ BBSName, Key, Key, Key, Key, Key, Key, Key, Key);
+ *RLen = len;
+ return;
+ }
+
+ return;
+ }
+
+ if (_stricmp(NodeURL, "/Mail/WPInfo.txt") == 0)
+ {
+ int i = 0, n, len = 0;
+ WPRec * WP[10000];
+
+ // Get array of addresses
+
+ for (n = 1; n <= NumberofWPrecs; n++)
+ {
+ WP[i++] = WPRecPtr[n];
+ if (i > 9999) break;
+ }
+
+ qsort((void *)WP, i, sizeof(void *), compare);
+
+ for (i=0; i < NumberofWPrecs; i++)
+ {
+ len += sprintf(&Reply[len], "%s|", WP[i]->callsign);
+ }
+
+ *RLen = len;
+ return;
+ }
+
+
+ ReplyLen = sprintf(Reply, MailSignon, BBSName, BBSName);
+ *RLen = ReplyLen;
+
+}
+
+int SendWPDetails(WPRec * WP, char * Reply, char * Key)
+{
+ int len = 0;
+ char D1[80], D2[80];
+
+ if (WP)
+ {
+ strcpy(D1, FormatDateAndTime(WP->last_modif, FALSE));
+ strcpy(D2, FormatDateAndTime(WP->last_seen, FALSE));
+
+ len = sprintf(Reply, WPDetail, Key, WP->callsign, WP->name,
+ WP->first_homebbs, WP->secnd_homebbs,
+ WP->first_qth, WP->secnd_qth,
+ WP->first_zip, WP->secnd_zip, D1, D2,
+ WP->Type,
+ WP->changed,
+ WP->seen);
+ }
+ return(len);
+}
+VOID SaveWP(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key)
+{
+ WPRec * WP = Session->WP;
+ char * input, * ptr1, * ptr2;
+ int n;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ if (strcmp(input + 4, "Delete") == 0)
+ {
+ for (n = 1; n <= NumberofWPrecs; n++)
+ {
+ if (Session->WP == WPRecPtr[n])
+ break;
+ }
+
+ if (n <= NumberofWPrecs)
+ {
+ WP = Session->WP;
+
+ for (n = n; n < NumberofWPrecs; n++)
+ {
+ WPRecPtr[n] = WPRecPtr[n+1]; // move down all following entries
+ }
+
+ NumberofWPrecs--;
+
+ free(WP);
+
+ SaveWPDatabase();
+
+ Session->WP = WPRecPtr[1];
+ }
+ *RLen = SendWPDetails(Session->WP, Reply, Session->Key);
+ return;
+ }
+ }
+ if (input && WP)
+ {
+ ptr1 = input + 4;
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 12) ptr1[12] = 0;strcpy(WP->name, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 40) ptr1[40] = 0;strcpy(WP->first_homebbs, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 40) ptr1[40] = 0;strcpy(WP->secnd_homebbs, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 30) ptr1[30] = 0;strcpy(WP->first_qth, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 30) ptr1[30] = 0;strcpy(WP->secnd_qth, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 8) ptr1[8] = 0;strcpy(WP->first_zip, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;if (strlen(ptr1) > 8) ptr1[8] = 0;strcpy(WP->secnd_zip, ptr1);ptr1 = ptr2;}
+
+ // GetParam(input, "BBSCall=", BBSName);
+
+
+/*
+ GetDlgItemText(hDlg, IDC_WPNAME, WP->name, 13);
+ GetDlgItemText(hDlg, IDC_HOMEBBS1, WP->first_homebbs, 41);
+ GetDlgItemText(hDlg, IDC_HOMEBBS2, WP->first_homebbs, 41);
+ GetDlgItemText(hDlg, IDC_QTH1, WP->first_qth, 31);
+ GetDlgItemText(hDlg, IDC_QTH2, WP->secnd_qth, 31);
+ GetDlgItemText(hDlg, IDC_ZIP1, WP->first_zip, 31);
+ GetDlgItemText(hDlg, IDC_ZIP2, WP->secnd_zip, 31);
+ WP->seen = GetDlgItemInt(hDlg, IDC_SEEN, &OK1, FALSE);
+*/
+
+ WP->last_modif = time(NULL);
+ WP->Type = 'U';
+ WP->changed = 1;
+
+ SaveWPDatabase();
+
+ *RLen = SendWPDetails(WP, Reply, Key);
+ }
+}
+
+
+int SendMessageDetails(struct MsgInfo * Msg, char * Reply, char * Key)
+{
+ int BBSNo = 1, x, y, len = 0;
+ char D1[80], D2[80], D3[80];
+ struct UserInfo * USER;
+ int i = 0, n;
+ struct UserInfo * bbs[NBBBS+2] = {0};
+
+ if (Msg)
+ {
+ char EmailFromLine[256] = "";
+
+ strcpy(D1, FormatDateAndTime((time_t)Msg->datecreated, FALSE));
+ strcpy(D2, FormatDateAndTime((time_t)Msg->datereceived, FALSE));
+ strcpy(D3, FormatDateAndTime((time_t)Msg->datechanged, FALSE));
+
+// if (Msg->emailfrom[0])
+ sprintf(EmailFromLine, "Email From
", Msg->emailfrom);
+
+ len = sprintf(Reply, MailDetailPage, Msg->number, Key,
+ Msg->from, D1,
+ (Msg->type == 'B')?sel:"",
+ (Msg->type == 'P')?sel:"",
+ (Msg->type == 'T')?sel:"",
+ Msg->to, D2,
+ (Msg->status == 'N')?sel:"",
+ (Msg->status == 'Y')?sel:"",
+ (Msg->status == 'F')?sel:"",
+ (Msg->status == 'K')?sel:"",
+ (Msg->status == 'H')?sel:"",
+ (Msg->status == 'D')?sel:"",
+ (Msg->status == '$')?sel:"",
+ Msg->bid, D3, Msg->length, EmailFromLine, Msg->via, Msg->title,
+ Key, Msg->number, Key, Key,
+ (Msg->B2Flags & Attachments)?"":"disabled");
+
+ // Get a sorted list of BBS records
+
+ for (n = 1; n <= NumberofUsers; n++)
+ {
+ USER = UserRecPtr[n];
+
+ if ((USER->flags & F_BBS))
+ if (USER->BBSNumber)
+ bbs[i++] = USER;
+ }
+
+ qsort((void *)bbs, i, sizeof(void *), compare );
+
+ n = 0;
+
+ for (y = 0; y < NBBBS/8; y++)
+ {
+ len += sprintf(&Reply[len],"");
+ for (x= 0; x < 8; x++)
+ {
+ char * Colour = NotThisOne;
+
+ if (bbs[n])
+ {
+ if (memcmp(Msg->fbbs, zeros, NBMASK) != 0)
+ if (check_fwd_bit(Msg->fbbs, bbs[n]->BBSNumber))
+ Colour = ToSend;
+ if (memcmp(Msg->forw, zeros, NBMASK) != 0)
+ if (check_fwd_bit(Msg->forw, bbs[n]->BBSNumber))
+ Colour = Sent;
+
+ len += sprintf(&Reply[len],"| %s | ",
+ Colour, bbs[n]->BBSNumber, bbs[n]->Call);
+ }
+ else
+ len += sprintf(&Reply[len], " | ");
+
+ n++;
+ }
+ len += sprintf(&Reply[len],"
");
+ if (n > i)
+ break;
+ }
+ len += sprintf(&Reply[len], "%s", MailDetailTail);
+ }
+ return(len);
+}
+
+char ** GetMultiStringInput(char * input, char * key)
+{
+ char MultiString[16384] = "";
+
+ GetParam(input, key, MultiString);
+
+ if (MultiString[0] == 0)
+ return NULL;
+
+ return SeparateMultiString(MultiString, TRUE);
+}
+
+char ** SeparateMultiString(char * MultiString, BOOL NoToUpper)
+{
+ char * ptr1 = MultiString;
+ char * ptr2 = NULL;
+ char * DecodedString;
+ char ** Value;
+ int Count = 0;
+ char c;
+ char * ptr;
+
+ ptr2 = zalloc(strlen(MultiString) + 1);
+ DecodedString = ptr2;
+
+ // Input has crlf or lf - replace with |
+
+ while (*ptr1)
+ {
+ c = *(ptr1++);
+
+ if (c == 13)
+ continue;
+
+ if (c == 10)
+ {
+ *ptr2++ = '|';
+ }
+ else
+ *(ptr2++) = c;
+ }
+
+ // Convert to string array
+
+ Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values
+ Value[0] = NULL;
+
+ ptr = DecodedString;
+
+ while (ptr && strlen(ptr))
+ {
+ ptr1 = strchr(ptr, '|');
+
+ if (ptr1)
+ *(ptr1++) = 0;
+
+ if (strlen(ptr))
+ {
+ Value = realloc(Value, (Count+2) * sizeof(void *));
+ if (_memicmp(ptr, "file ", 5) == 0 || NoToUpper)
+ Value[Count++] = _strdup(ptr);
+ else
+ Value[Count++] = _strupr(_strdup(ptr));
+ }
+ ptr = ptr1;
+ }
+
+ Value[Count] = NULL;
+ return Value;
+}
+
+VOID GetMallocedParam(char * input, char * key, char ** value)
+{
+ char Param[32768] = "";
+
+ GetParam(input, key, Param);
+
+ if (Param[0])
+ {
+ free(*value);
+ *value = _strdup(Param);
+ }
+}
+
+VOID GetParam(char * input, char * key, char * value)
+{
+ char * ptr = strstr(input, key);
+ char Param[32768];
+ char * ptr1, * ptr2;
+ char c;
+
+ if (ptr)
+ {
+ ptr2 = strchr(ptr, '&');
+ if (ptr2) *ptr2 = 0;
+ strcpy(Param, ptr + strlen(key));
+ if (ptr2) *ptr2 = '&'; // Restore string
+
+ // Undo any % transparency
+
+ ptr1 = Param;
+ ptr2 = Param;
+
+ c = *(ptr1++);
+
+ while (c)
+ {
+ if (c == '%')
+ {
+ int n;
+ int m = *(ptr1++) - '0';
+ if (m > 9) m = m - 7;
+ n = *(ptr1++) - '0';
+ if (n > 9) n = n - 7;
+
+ *(ptr2++) = m * 16 + n;
+ }
+ else if (c == '+')
+ *(ptr2++) = ' ';
+ else
+ *(ptr2++) = c;
+
+ c = *(ptr1++);
+ }
+
+ *(ptr2++) = 0;
+
+ strcpy(value, Param);
+ }
+}
+
+VOID GetCheckBox(char * input, char * key, int * value)
+{
+ char * ptr = strstr(input, key);
+ if (ptr)
+ *value = 1;
+ else
+ *value = 0;
+}
+
+
+VOID * GetOverrideFromString(char * input)
+{
+ char * ptr1;
+ char * MultiString = NULL;
+ char * ptr = input;
+ int Count = 0;
+ struct Override ** Value;
+ char * Val;
+
+ Value = zalloc(sizeof(void *)); // always NULL entry on end even if no values
+ Value[0] = NULL;
+
+ while (ptr && strlen(ptr))
+ {
+ ptr1 = strchr(ptr, 13);
+
+ if (ptr1)
+ {
+ *(ptr1) = 0;
+ ptr1 += 2;
+ }
+ Value = realloc(Value, (Count+2) * sizeof(void *));
+ Value[Count] = zalloc(sizeof(struct Override));
+ Val = strlop(ptr, ',');
+ if (Val == NULL)
+ break;
+
+ Value[Count]->Call = _strupr(_strdup(ptr));
+ Value[Count++]->Days = atoi(Val);
+ ptr = ptr1;
+ }
+
+ Value[Count] = NULL;
+ return Value;
+}
+
+
+
+
+VOID SaveHousekeeping(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key)
+{
+ int ReplyLen = 0;
+ char * input;
+ char Temp[80];
+ struct tm *tm;
+ time_t now;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "RunNow="))
+ {
+ DoHouseKeeping(FALSE);
+ SendHouseKeeping(Reply, RLen, Key);
+ return;
+ }
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ SendHouseKeeping(Reply, RLen, Key);
+ return;
+ }
+
+ GetParam(input, "MTTime=", Temp);
+ MaintTime = atoi(Temp);
+ GetParam(input, "MTInt=", Temp);
+ MaintInterval = atoi(Temp);
+ GetParam(input, "MAXMSG=", Temp);
+ MaxMsgno = atoi(Temp);
+ GetParam(input, "BIDLife=", Temp);
+ BidLifetime= atoi(Temp);
+ GetParam(input, "MaxAge=", Temp);
+ MaxAge = atoi(Temp);
+ GetParam(input, "LogLife=", Temp);
+ LogAge = atoi(Temp);
+ GetParam(input, "UserLife=", Temp);
+ UserLifetime= atoi(Temp);
+
+ GetCheckBox(input, "Deltobin=", &DeletetoRecycleBin);
+ GetCheckBox(input, "SendND=", &SendNonDeliveryMsgs);
+ GetCheckBox(input, "NoMail=", &SuppressMaintEmail);
+ GetCheckBox(input, "GenTraffic=", &GenerateTrafficReport);
+ GetCheckBox(input, "OvUnsent=", &OverrideUnsent);
+
+ GetParam(input, "PR=", Temp);
+ PR = atof(Temp);
+ GetParam(input, "PUR=", Temp);
+ PUR = atof(Temp);
+ GetParam(input, "PF=", Temp);
+ PF = atof(Temp);
+ GetParam(input, "PUF=", Temp);
+ PNF = atof(Temp);
+ GetParam(input, "BF=", Temp);
+ BF = atoi(Temp);
+ GetParam(input, "BUF=", Temp);
+ BNF = atoi(Temp);
+
+ GetParam(input, "NTSD=", Temp);
+ NTSD = atoi(Temp);
+
+ GetParam(input, "NTSF=", Temp);
+ NTSF = atoi(Temp);
+
+ GetParam(input, "NTSU=", Temp);
+ NTSU = atoi(Temp);
+
+ GetParam(input, "From=", LTFROMString);
+ LTFROM = GetOverrideFromString(LTFROMString);
+
+ GetParam(input, "To=", LTTOString);
+ LTTO = GetOverrideFromString(LTTOString);
+
+ GetParam(input, "At=", LTATString);
+ LTAT = GetOverrideFromString(LTATString);
+
+ SaveConfig(ConfigName);
+ GetConfig(ConfigName);
+
+ // Calulate time to run Housekeeping
+
+ now = time(NULL);
+
+ tm = gmtime(&now);
+
+ tm->tm_hour = MaintTime / 100;
+ tm->tm_min = MaintTime % 100;
+ tm->tm_sec = 0;
+
+// MaintClock = _mkgmtime(tm);
+ MaintClock = mktime(tm) - (time_t)_MYTIMEZONE;
+
+ while (MaintClock < now)
+ MaintClock += MaintInterval * 3600;
+
+ Debugprintf("Maint Clock %d NOW %d Time to HouseKeeping %d", MaintClock, now, MaintClock - now);
+ }
+ SendHouseKeeping(Reply, RLen, Key);
+ return;
+}
+
+
+
+
+
+
+
+VOID SaveWelcome(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key)
+{
+ int ReplyLen = 0;
+ char * input;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ GetMallocedParam(input, "NUWelcome=", &WelcomeMsg);
+ GetMallocedParam(input, "NewWelcome=", &NewWelcomeMsg);
+ GetMallocedParam(input, "ExWelcome=", &ExpertWelcomeMsg);
+
+ TidyWelcomeMsg(&WelcomeMsg);
+ TidyWelcomeMsg(&NewWelcomeMsg);
+ TidyWelcomeMsg(&ExpertWelcomeMsg);
+
+ GetMallocedParam(input, "NUPrompt=", &Prompt);
+ GetMallocedParam(input, "NewPrompt=", &NewPrompt);
+ GetMallocedParam(input, "ExPrompt=", &ExpertPrompt);
+ TidyPrompts();
+
+ GetParam(input, "Bye=", &SignoffMsg[0]);
+ if (SignoffMsg[0])
+ {
+ if (SignoffMsg[strlen(SignoffMsg) - 1] == 10)
+ SignoffMsg[strlen(SignoffMsg) - 1] = 0;
+
+ if (SignoffMsg[strlen(SignoffMsg) - 1] != 13)
+ strcat(SignoffMsg, "\r");
+ }
+
+ if (SignoffMsg[0] == 13)
+ SignoffMsg[0] = 0;
+ }
+
+ SendWelcomePage(Reply, RLen, Key);
+ return;
+}
+
+VOID ProcessConfUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key)
+{
+ int ReplyLen = 0;
+ char * input;
+ struct UserInfo * USER = NULL;
+ char Temp[80];
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ if (strstr(input, "ConfigUI=Config+UI"))
+ {
+ SendUIPage(Reply, RLen, Key);
+ return;
+ }
+
+ GetParam(input, "BBSCall=", BBSName);
+ _strupr(BBSName);
+ strlop(BBSName, '-');
+ GetParam(input, "SYSOPCall=", SYSOPCall);
+ _strupr(SYSOPCall);
+ strlop(SYSOPCall, '-');
+ GetParam(input, "HRoute=", HRoute);
+ _strupr(HRoute);
+ GetParam(input, "ApplNum=", Temp);
+ BBSApplNum = atoi(Temp);
+ GetParam(input, "Streams=", Temp);
+ MaxStreams = atoi(Temp);
+
+ GetCheckBox(input, "SysToSYSOP=", &SendSYStoSYSOPCall);
+ GetCheckBox(input, "BBSToSYSOP=", &SendBBStoSYSOPCall);
+ GetCheckBox(input, "RefuseBulls=", &RefuseBulls);
+ GetCheckBox(input, "EnUI=", &EnableUI);
+
+ GetParam(input, "UIInterval=", Temp);
+ MailForInterval = atoi(Temp);
+
+ GetCheckBox(input, "DontHold=", &DontHoldNewUsers);
+ GetCheckBox(input, "DefaultNoWinlink=", &DefaultNoWINLINK);
+ GetCheckBox(input, "DontNeedName=", &AllowAnon);
+ GetCheckBox(input, "DontNeedHomeBBS=", &DontNeedHomeBBS);
+ GetCheckBox(input, "DontCheckFromCall=", &DontCheckFromCall);
+ GetCheckBox(input, "UserCantKillT=", &UserCantKillT);
+ UserCantKillT = !UserCantKillT; // Reverse Logic
+ GetCheckBox(input, "FWDtoMe=", &ForwardToMe);
+ GetCheckBox(input, "OnlyKnown=", &OnlyKnown);
+ GetCheckBox(input, "Events=", &reportMailEvents);
+
+ GetParam(input, "POP3Port=", Temp);
+ POP3InPort = atoi(Temp);
+
+ GetParam(input, "SMTPPort=", Temp);
+ SMTPInPort = atoi(Temp);
+
+ GetParam(input, "NNTPPort=", Temp);
+ NNTPInPort = atoi(Temp);
+
+ GetCheckBox(input, "EnRemote=", &RemoteEmail);
+
+ GetCheckBox(input, "EnISP=", &ISP_Gateway_Enabled);
+ GetCheckBox(input, "SendAMPR=", &SendAMPRDirect);
+
+ GetParam(input, "AMPRDomain=", AMPRDomain);
+
+ GetParam(input, "ISPDomain=", MyDomain);
+ GetParam(input, "SMTPServer=", ISPSMTPName);
+ GetParam(input, "ISPEHLOName=", ISPEHLOName);
+
+ GetParam(input, "ISPSMTPPort=", Temp);
+ ISPSMTPPort = atoi(Temp);
+
+ GetParam(input, "POP3Server=", ISPPOP3Name);
+
+ GetParam(input, "ISPPOP3Port=", Temp);
+ ISPPOP3Port = atoi(Temp);
+
+ GetParam(input, "ISPAccount=", ISPAccountName);
+
+ GetParam(input, "ISPPassword=", ISPAccountPass);
+ EncryptedPassLen = EncryptPass(ISPAccountPass, EncryptedISPAccountPass);
+
+ GetParam(input, "PollInterval=", Temp);
+ ISPPOP3Interval = atoi(Temp);
+
+ GetCheckBox(input, "ISPAuth=", &SMTPAuthNeeded);
+
+ GetCheckBox(input, "EnWP=", &SendWP);
+ GetCheckBox(input, "RejWFBulls=", &FilterWPBulls);
+
+ if (strstr(input, "Type=TypeB"))
+ SendWPType = 0;
+
+ if (strstr(input, "Type=TypeP"))
+ SendWPType = 1;
+
+ SendWPAddrs = GetMultiStringInput(input, "WPTO=");
+
+ RejFrom = GetMultiStringInput(input, "Rfrom=");
+ RejTo = GetMultiStringInput(input, "Rto=");
+ RejAt = GetMultiStringInput(input, "Rat=");
+ RejBID = GetMultiStringInput(input, "RBID=");
+ HoldFrom = GetMultiStringInput(input, "Hfrom=");
+ HoldTo = GetMultiStringInput(input, "Hto=");
+ HoldAt = GetMultiStringInput(input, "Hat=");
+ HoldBID = GetMultiStringInput(input, "HBID=");
+
+ // Look for fbb style filters
+
+ input = strstr(input, "&Action=");
+
+ // delete old list
+
+ while(Filters && Filters->Next)
+ {
+ FBBFilter * next = Filters->Next;
+ free(Filters);
+ Filters = next;
+ }
+
+ free(Filters);
+ Filters = NULL;
+
+ while (input)
+ {
+ // extract and validate before saving
+
+ FBBFilter Filter;
+ FBBFilter * PFilter;
+
+ memset(&Filter, 0, sizeof(FBBFilter));
+
+ Filter.Action = toupper(input[8]);
+
+ input = strstr(input, "&Type=");
+
+ if (Filter.Action == 'H' || Filter.Action == 'R')
+ {
+ Filter.Type = toupper(input[6]);
+ input = strstr(input, "&From=");
+ memcpy(Filter.From, &input[6], 10);
+ input = strstr(input, "&TO=");
+ strlop(Filter.From, '&');
+ _strupr(Filter.From);
+ memcpy(Filter.TO, &input[4], 10);
+ input = strstr(input, "&AT=");
+ strlop(Filter.TO, '&');
+ _strupr(Filter.TO);
+ memcpy(Filter.AT, &input[4], 10);
+ input = strstr(input, "&BID=");
+ strlop(Filter.AT, '&');
+ _strupr(Filter.AT);
+ memcpy(Filter.BID, &input[5], 10);
+ input = strstr(input, "&MaxLen=");
+ strlop(Filter.BID, '&');
+ _strupr(Filter.BID);
+ Filter.MaxLen = atoi(&input[8]);
+
+ if (Filter.Type == '&') Filter.Type = '*';
+ if (Filter.From[0] == 0) strcpy(Filter.From, "*");
+ if (Filter.TO[0] == 0) strcpy(Filter.TO, "*");
+ if (Filter.AT[0] == 0) strcpy(Filter.AT, "*");
+ if (Filter.BID[0] == 0) strcpy(Filter.BID, "*");
+
+ // add to list
+
+ PFilter = zalloc(sizeof(FBBFilter));
+
+ memcpy(PFilter, &Filter, sizeof(FBBFilter));
+
+ if (Filters == 0)
+ Filters = PFilter;
+ else
+ {
+ FBBFilter * p = Filters;
+
+ while (p->Next)
+ p = p->Next;
+
+ p->Next = PFilter;
+ }
+ }
+
+ input = strstr(input, "&Action=");
+ }
+
+ SaveConfig(ConfigName);
+ GetConfig(ConfigName);
+ }
+
+ SendConfigPage(Reply, RLen, Key);
+ return;
+}
+
+
+
+VOID ProcessUIUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Key)
+{
+ int ReplyLen = 0, i;
+ char * input;
+ struct UserInfo * USER = NULL;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ GetParam(input, "MailFor=", &MailForText[0]);
+
+ for (i = 1; i <= GetNumberofPorts(); i++)
+ {
+ char EnKey[10];
+ char DigiKey[10];
+ char MFKey[12];
+ char HDDRKey[12];
+ char NullKey[12];
+ char Temp[100];
+
+ sprintf(EnKey, "En%d=", i);
+ sprintf(DigiKey, "Path%d=", i);
+ sprintf(MFKey, "SndMF%d=", i);
+ sprintf(HDDRKey, "SndHDDR%d=", i);
+ sprintf(NullKey, "SndNull%d=", i);
+
+ GetCheckBox(input, EnKey, &UIEnabled[i]);
+ GetParam(input, DigiKey, Temp);
+ if (UIDigi[i])
+ free (UIDigi[i]);
+ UIDigi[i] = _strdup(Temp);
+ GetCheckBox(input, MFKey, &UIMF[i]);
+ GetCheckBox(input, HDDRKey, &UIHDDR[i]);
+ GetCheckBox(input, NullKey, &UINull[i]);
+ }
+
+ SaveConfig(ConfigName);
+ GetConfig(ConfigName);
+ }
+
+ SendUIPage(Reply, RLen, Key);
+ return;
+}
+
+VOID ProcessDisUser(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ char * input;
+ char * ptr;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ ptr = strstr(input, "call=");
+ if (ptr)
+ {
+ int Stream = atoi(ptr + 5);
+ Disconnect(Stream);
+ }
+ }
+ SendStatusPage(Reply, RLen, Rest);
+}
+
+
+
+VOID SaveFwdCommon(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ struct UserInfo * USER = NULL;
+
+ char Temp[80];
+ int Mask = 0;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ int n;
+ GetParam(input, "MaxTX=", Temp);
+ MaxTXSize = atoi(Temp);
+ GetParam(input, "MaxRX=", Temp);
+ MaxRXSize = atoi(Temp);
+ GetParam(input, "MaxAge=", Temp);
+ MaxAge = atoi(Temp);
+ GetCheckBox(input, "WarnNoRoute=", &WarnNoRoute);
+ GetCheckBox(input, "LocalTime=", &Localtime);
+ GetCheckBox(input, "SendPtoMultiple=", &SendPtoMultiple);
+
+ // Reinitialise Aliases
+
+ n = 0;
+
+ if (Aliases)
+ {
+ while(Aliases[n])
+ {
+ free(Aliases[n]->Dest);
+ free(Aliases[n]);
+ n++;
+ }
+
+ free(Aliases);
+ Aliases = NULL;
+ FreeList(AliasText);
+ }
+
+ AliasText = GetMultiStringInput(input, "Aliases=");
+
+ if (AliasText)
+ {
+ n = 0;
+
+ while (AliasText[n])
+ {
+ _strupr(AliasText[n]);
+ n++;
+ }
+ }
+ SetupFwdAliases();
+ }
+
+ SaveConfig(ConfigName);
+ GetConfig(ConfigName);
+
+ SendFwdMainPage(Reply, RLen, Session->Key);
+}
+
+char * GetNextParam(char ** next)
+{
+ char * ptr1 = *next;
+ char * ptr2 = strchr(ptr1, '|');
+ if (ptr2)
+ {
+ *(ptr2++) = 0;
+ *next = ptr2;
+ }
+ return ptr1;
+}
+
+VOID SaveFwdDetails(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ struct UserInfo * USER = Session->User;
+ struct BBSForwardingInfo * FWDInfo = USER->ForwardingInfo;
+ char * ptr1, *ptr2;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "StartForward"))
+ {
+ StartForwarding(USER->BBSNumber, NULL);
+ SendFwdDetails(Session->User, Reply, RLen, Session->Key);
+ return;
+ }
+
+ if (strstr(input, "CopyForward"))
+ {
+ struct UserInfo * OldBBS;
+
+ // Get call to copy from
+
+ ptr2 = input + 4;
+ ptr1 = GetNextParam(&ptr2); // Call
+ _strupr(ptr2);
+
+ OldBBS = FindBBS(ptr2);
+
+ if (OldBBS == NULL)
+ {
+
+ *RLen = sprintf(Reply, "Copy From BBS %s not found
", ptr2);
+ return;
+ }
+
+ // Set current info from OldBBS
+//
+// SetForwardingPage(hDlg, OldBBS); // moved to separate routine as also called from copy config
+
+ SendFwdDetails(OldBBS, Reply, RLen, Session->Key);
+ return;
+ }
+ // Fwd update
+
+ ptr2 = input + 4;
+ ptr1 = GetNextParam(&ptr2); // TO
+ FWDInfo->TOCalls = SeparateMultiString(ptr1, FALSE);
+
+ ptr1 = GetNextParam(&ptr2); // AT
+ FWDInfo->ATCalls = SeparateMultiString(ptr1, FALSE);
+
+ ptr1 = GetNextParam(&ptr2); // TIMES
+ FWDInfo->FWDTimes = SeparateMultiString(ptr1, FALSE);
+
+ ptr1 = GetNextParam(&ptr2); // FWD SCRIPT
+ FWDInfo->ConnectScript = SeparateMultiString(ptr1, TRUE);
+
+ ptr1 = GetNextParam(&ptr2); // HRB
+ FWDInfo->Haddresses = SeparateMultiString(ptr1, FALSE);
+
+ ptr1 = GetNextParam(&ptr2); // HRP
+ FWDInfo->HaddressesP = SeparateMultiString(ptr1, FALSE);
+
+ ptr1 = GetNextParam(&ptr2); // BBSHA
+ if (FWDInfo->BBSHA)
+ free(FWDInfo->BBSHA);
+
+ FWDInfo->BBSHA = _strdup(_strupr(ptr1));
+
+ ptr1 = GetNextParam(&ptr2); // EnF
+ if (strcmp(ptr1, "true") == 0) FWDInfo->Enabled = TRUE; else FWDInfo->Enabled = FALSE;
+
+ ptr1 = GetNextParam(&ptr2); // Interval
+ FWDInfo->FwdInterval = atoi(ptr1);
+
+ ptr1 = GetNextParam(&ptr2); // EnR
+ if (strcmp(ptr1, "true") == 0) FWDInfo->ReverseFlag = TRUE; else FWDInfo->ReverseFlag = FALSE;
+
+ ptr1 = GetNextParam(&ptr2); // RInterval
+ FWDInfo->RevFwdInterval = atoi(ptr1);
+
+ ptr1 = GetNextParam(&ptr2); // No Wait
+ if (strcmp(ptr1, "true") == 0) FWDInfo->SendNew = TRUE; else FWDInfo->SendNew = FALSE;
+
+ ptr1 = GetNextParam(&ptr2); // Blocked
+ if (strcmp(ptr1, "true") == 0) FWDInfo->AllowBlocked = TRUE; else FWDInfo->AllowBlocked = FALSE;
+
+ ptr1 = GetNextParam(&ptr2); // FBB Block
+ FWDInfo->MaxFBBBlockSize = atoi(ptr1);
+
+ ptr1 = GetNextParam(&ptr2); // Personals
+ if (strcmp(ptr1, "true") == 0) FWDInfo->PersonalOnly = TRUE; else FWDInfo->PersonalOnly = FALSE;
+ ptr1 = GetNextParam(&ptr2); // Binary
+ if (strcmp(ptr1, "true") == 0) FWDInfo->AllowCompressed = TRUE; else FWDInfo->AllowCompressed = FALSE;
+ ptr1 = GetNextParam(&ptr2); // B1
+ if (strcmp(ptr1, "true") == 0) FWDInfo->AllowB1 = TRUE; else FWDInfo->AllowB1 = FALSE;
+ ptr1 = GetNextParam(&ptr2); // B2
+ if (strcmp(ptr1, "true") == 0) FWDInfo->AllowB2 = TRUE; else FWDInfo->AllowB2 = FALSE;
+ ptr1 = GetNextParam(&ptr2); // CTRLZ
+ if (strcmp(ptr1, "true") == 0) FWDInfo->SendCTRLZ = TRUE; else FWDInfo->SendCTRLZ = FALSE;
+ ptr1 = GetNextParam(&ptr2); // Connect Timeout
+ FWDInfo->ConTimeout = atoi(ptr1);
+
+ SaveConfig(ConfigName);
+ GetConfig(ConfigName);
+
+ ReinitializeFWDStruct(Session->User);
+
+ SendFwdDetails(Session->User, Reply, RLen, Session->Key);
+ }
+}
+
+
+
+VOID ProcessUserUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ struct UserInfo * USER = Session->User;
+ int SSID, Mask = 0;
+ char * ptr1, *ptr2;
+ int skipRMSExUser = 0;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel"))
+ {
+ *RLen = SendHeader(Reply, Session->Key);
+ return;
+ }
+
+ if (strstr(input, "Delete"))
+ {
+ int n;
+
+ for (n = 1; n <= NumberofUsers; n++)
+ {
+ if (Session->User == UserRecPtr[n])
+ break;
+ }
+
+ if (n <= NumberofUsers)
+ {
+ USER = Session->User;
+
+ for (n = n; n < NumberofUsers; n++)
+ {
+ UserRecPtr[n] = UserRecPtr[n+1]; // move down all following entries
+ }
+
+ NumberofUsers--;
+
+ if (USER->flags & F_BBS) // was a BBS?
+ DeleteBBS(USER);
+
+ free(USER);
+
+ SaveUserDatabase();
+
+ Session->User = UserRecPtr[1];
+
+ SendUserSelectPage(Reply, RLen, Session->Key);
+ return;
+ }
+ }
+
+ if (strstr(input, "Add="))
+ {
+ char * Call;
+
+ Call = input + 8;
+ strlop(Call, '-');
+
+ if (strlen(Call) > 6)
+ Call[6] = 0;
+
+ _strupr(Call);
+
+ if (Call[0] == 0 || LookupCall(Call))
+ {
+ // Null or exists
+
+ SendUserSelectPage(Reply, RLen, Session->Key);
+ return;
+ }
+
+ USER = AllocateUserRecord(Call);
+ USER->Temp = zalloc(sizeof (struct TempUserInfo));
+
+ SendUserSelectPage(Reply, RLen, Session->Key);
+ return;
+
+ }
+
+ // User update
+
+ ptr2 = input + 4;
+ ptr1 = GetNextParam(&ptr2); // BBS
+
+ // If BBS Flag has changed, must set up or delete forwarding info
+
+ if (strcmp(ptr1, "true") == 0)
+ {
+ if ((USER->flags & F_BBS) == 0)
+ {
+ // New BBS
+
+ if(SetupNewBBS(USER))
+ {
+ USER->flags |= F_BBS;
+ USER->flags &= ~F_Temp_B2_BBS; // Clear RMS Express User
+ skipRMSExUser = 1; // Dont read old value
+ }
+ else
+ {
+ // Failed - too many bbs's defined
+
+ //sprintf(InfoBoxText, "Cannot set user to be a BBS - you already have 80 BBS's defined");
+ //DialogBox(hInst, MAKEINTRESOURCE(IDD_USERADDED_BOX), hWnd, InfoDialogProc);
+ USER->flags &= ~F_BBS;
+ //CheckDlgButton(hDlg, IDC_BBSFLAG, (user->flags & F_BBS));
+ }
+ }
+ }
+ else
+ {
+ if (USER->flags & F_BBS)
+ {
+ //was a BBS
+
+ USER->flags &= ~F_BBS;
+ DeleteBBS(USER);
+ }
+ }
+
+ ptr1 = GetNextParam(&ptr2); // Permit Email
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_EMAIL; else USER->flags &= ~F_EMAIL;
+
+ ptr1 = GetNextParam(&ptr2); // PMS
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_PMS; else USER->flags &= ~F_PMS;
+
+ ptr1 = GetNextParam(&ptr2); // RMS EX User
+ if (strcmp(ptr1, "true") == 0 && !skipRMSExUser) USER->flags |= F_Temp_B2_BBS; else USER->flags &= ~F_Temp_B2_BBS;
+ ptr1 = GetNextParam(&ptr2); // SYSOP
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_SYSOP; else USER->flags &= ~F_SYSOP;
+ ptr1 = GetNextParam(&ptr2); // PollRMS
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_POLLRMS; else USER->flags &= ~F_POLLRMS;
+ ptr1 = GetNextParam(&ptr2); // Expert
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_Expert; else USER->flags &= ~F_Expert;
+
+ ptr1 = GetNextParam(&ptr2); // SSID1
+ SSID = atoi(ptr1);
+ Mask |= (1 << SSID);
+ ptr1 = GetNextParam(&ptr2); // SSID2
+ SSID = atoi(ptr1);
+ Mask |= (1 << SSID);
+ ptr1 = GetNextParam(&ptr2); // SSID3
+ SSID = atoi(ptr1);
+ Mask |= (1 << SSID);
+ ptr1 = GetNextParam(&ptr2); // SSID4
+ SSID = atoi(ptr1);
+ Mask |= (1 << SSID);
+ Session->User->RMSSSIDBits = Mask;
+
+ ptr1 = GetNextParam(&ptr2); // Excluded
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_Excluded; else USER->flags &= ~F_Excluded;
+ ptr1 = GetNextParam(&ptr2); // Hold
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_HOLDMAIL; else USER->flags &= ~F_HOLDMAIL;
+ ptr1 = GetNextParam(&ptr2); // SYSOP gets LM
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_SYSOP_IN_LM; else USER->flags &= ~F_SYSOP_IN_LM;
+ ptr1 = GetNextParam(&ptr2); // Dont add winlink.org
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_NOWINLINK; else USER->flags &= ~F_NOWINLINK;
+ ptr1 = GetNextParam(&ptr2); // Allow Bulls
+ if (strcmp(ptr1, "true") == 0) USER->flags &= ~F_NOBULLS; else USER->flags |= F_NOBULLS; // Inverted flag
+ ptr1 = GetNextParam(&ptr2); // NTS Message Pickup Station
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_NTSMPS; else USER->flags &= ~F_NTSMPS;
+ ptr1 = GetNextParam(&ptr2); // APRS Mail For
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_RMSREDIRECT; else USER->flags &= ~F_RMSREDIRECT;
+ ptr1 = GetNextParam(&ptr2); // Redirect to RMS
+
+ if (strcmp(ptr1, "true") == 0) USER->flags |= F_APRSMFOR; else USER->flags &= ~F_APRSMFOR;
+
+ ptr1 = GetNextParam(&ptr2); // APRS SSID
+ SSID = atoi(ptr1);
+ SSID &= 15;
+ USER->flags &= 0x0fffffff;
+ USER->flags |= (SSID << 28);
+
+
+ ptr1 = GetNextParam(&ptr2); // Last Listed
+ USER->lastmsg = atoi(ptr1);
+ ptr1 = GetNextParam(&ptr2); // Name
+ strcpy(USER->Name, ptr1);
+ ptr1 = GetNextParam(&ptr2); // Pass
+ strcpy(USER->pass, ptr1);
+ ptr1 = GetNextParam(&ptr2); // CMS Pass
+ if (memcmp("****************", ptr1, strlen(ptr1) != 0))
+ {
+ strcpy(USER->CMSPass, ptr1);
+ }
+
+ ptr1 = GetNextParam(&ptr2); // QTH
+ strcpy(USER->Address, ptr1);
+ ptr1 = GetNextParam(&ptr2); // ZIP
+ strcpy(USER->ZIP, ptr1);
+ ptr1 = GetNextParam(&ptr2); // HomeBBS
+ strcpy(USER->HomeBBS, ptr1);
+ _strupr(USER->HomeBBS);
+
+ SaveUserDatabase();
+ UpdateWPWithUserInfo(USER);
+
+ *RLen = SendUserDetails(Session, Reply, Session->Key);
+ }
+}
+
+VOID ProcessMsgAction(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ int BBSNumber = 0;
+ struct MsgInfo * Msg = Session->Msg;
+ char * ptr1;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input && Msg)
+ {
+ ptr1 = input + 4;
+ *RLen = SendMessageDetails(Msg, Reply, Session->Key);
+ }
+}
+
+VOID SaveMessageText(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ struct MsgInfo * Msg = Session->Msg;
+ char * ptr, * ptr1, * ptr2, *input;
+ char c;
+ int MsgLen, WriteLen;
+ char MsgFile[256];
+ FILE * hFile;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input)
+ {
+ if (strstr(input, "Cancel=Cancel"))
+ {
+ *RLen = sprintf(Reply, "%s", "");
+ return;
+ }
+
+ ptr = strstr(input, "&Save=");
+
+ if (ptr)
+ {
+ *ptr = 0;
+
+ // Undo any % transparency
+
+ ptr1 = ptr2 = input + 8;
+
+ c = *(ptr1++);
+
+ while (c)
+ {
+ if (c == '%')
+ {
+ int n;
+ int m = *(ptr1++) - '0';
+ if (m > 9) m = m - 7;
+ n = *(ptr1++) - '0';
+ if (n > 9) n = n - 7;
+
+ *(ptr2++) = m * 16 + n;
+ }
+ else if (c == '+')
+ *(ptr2++) = ' ';
+ else
+ *(ptr2++) = c;
+
+ c = *(ptr1++);
+ }
+
+ *(ptr2++) = 0;
+
+ MsgLen = (int)strlen(input + 8);
+
+ Msg->datechanged = time(NULL);
+ Msg->length = MsgLen;
+
+ sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
+
+ hFile = fopen(MsgFile, "wb");
+
+ if (hFile)
+ {
+ WriteLen = (int)fwrite(input + 8, 1, Msg->length, hFile);
+ fclose(hFile);
+ }
+
+ if (WriteLen != Msg->length)
+ {
+ char Mess[80];
+ sprintf_s(Mess, sizeof(Mess), "Failed to create Message File\r");
+ CriticalErrorHandler(Mess);
+
+ return;
+ }
+
+ SaveMessageDatabase();
+
+ *RLen = sprintf(Reply, "%s", "");
+
+ }
+ }
+ return;
+
+}
+
+
+VOID ProcessMsgUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ int BBSNumber = 0;
+ struct MsgInfo * Msg = Session->Msg;
+ char * ptr1, * ptr2;
+ char OldStatus = Msg->status;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input && Msg)
+ {
+ ptr1 = input + 4;
+ ptr2 = strchr(ptr1, '|');
+ if (ptr2)
+ {
+ *(ptr2++) = 0;
+ strcpy(Msg->from, ptr1);
+ ptr1 = ptr2;
+ }
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->to, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->bid, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->emailfrom, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->via, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;strcpy(Msg->title, ptr1);ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;Msg->type = *ptr1;ptr1 = ptr2;}
+ ptr2 = strchr(ptr1, '|');if (ptr2){*(ptr2++) = 0;Msg->status = *ptr1;ptr1 = ptr2;}
+
+ if (Msg->status != OldStatus)
+ {
+ // Need to take action if killing message
+
+ if (Msg->status == 'K')
+ FlagAsKilled(Msg, FALSE); // Clear forwarding bits
+ }
+
+ Msg->datechanged = time(NULL);
+ SaveMessageDatabase();
+ }
+
+ *RLen = SendMessageDetails(Msg, Reply, Session->Key);
+}
+
+
+
+
+VOID ProcessMsgFwdUpdate(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
+{
+ int ReplyLen = 0;
+ char * input;
+ int BBSNumber = 0;
+ struct UserInfo * User;
+ struct MsgInfo * Msg = Session->Msg;
+ BOOL toforward, forwarded;
+
+ input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
+
+ if (input && Msg)
+ {
+ BBSNumber = atoi(input + 4);
+ User = BBSLIST[BBSNumber];
+
+ if (User == NULL)
+ return;
+
+ toforward = check_fwd_bit(Msg->fbbs, BBSNumber);
+ forwarded = check_fwd_bit(Msg->forw, BBSNumber);
+
+ if (forwarded)
+ {
+ // Changing to not this BBS
+
+ clear_fwd_bit(Msg->forw, BBSNumber);
+ }
+ else if (toforward)
+ {
+ // Change to Forwarded
+
+ clear_fwd_bit(Msg->fbbs, BBSNumber);
+ User->ForwardingInfo->MsgCount--;
+ set_fwd_bit(Msg->forw, BBSNumber);
+ }
+ else
+ {
+ // Change to to forward
+
+ set_fwd_bit(Msg->fbbs, BBSNumber);
+ User->ForwardingInfo->MsgCount++;
+ clear_fwd_bit(Msg->forw, BBSNumber);
+ if (FirstMessageIndextoForward > Msg->number)
+ FirstMessageIndextoForward = Msg->number;
+
+ }
+ *RLen = SendMessageDetails(Msg, Reply, Session->Key);
+ }
+ SaveMessageDatabase();
+}
+
+
+
+
+VOID SetMultiStringValue(char ** values, char * Multi)
+{
+ char ** Calls;
+ char * ptr = &Multi[0];
+
+ *ptr = 0;
+
+ if (values)
+ {
+ Calls = values;
+
+ while(Calls[0])
+ {
+ strcpy(ptr, Calls[0]);
+ ptr += strlen(Calls[0]);
+ *(ptr++) = '\r';
+ *(ptr++) = '\n';
+ Calls++;
+ }
+ *(ptr) = 0;
+ }
+}
+
+
+
+VOID SendFwdDetails(struct UserInfo * User, char * Reply, int * ReplyLen, char * Key)
+{
+ int Len;
+ struct BBSForwardingInfo * FWDInfo = User->ForwardingInfo;
+ char TO[2048] = "";
+ char AT[2048] = "";
+ char TIMES[2048] = "";
+ char FWD[100000] = "";
+ char HRB[2048] = "";
+ char HRP[2048] = "";
+
+ SetMultiStringValue(FWDInfo->TOCalls, TO);
+ SetMultiStringValue(FWDInfo->ATCalls, AT);
+ SetMultiStringValue(FWDInfo->FWDTimes, TIMES);
+ SetMultiStringValue(FWDInfo->ConnectScript, FWD);
+ SetMultiStringValue(FWDInfo->Haddresses, HRB);
+ SetMultiStringValue(FWDInfo->HaddressesP, HRP);
+
+ if (FwdDetailTemplate == NULL)
+ FwdDetailTemplate = GetTemplateFromFile(3, "FwdDetail.txt");
+
+ Len = sprintf(Reply, FwdDetailTemplate, User->Call,
+ CountMessagestoForward (User), Key,
+ TO, AT, TIMES , FWD, HRB, HRP,
+ (FWDInfo->BBSHA) ? FWDInfo->BBSHA : "",
+ (FWDInfo->Enabled) ? CHKD : UNC,
+ FWDInfo->FwdInterval,
+ (FWDInfo->ReverseFlag) ? CHKD : UNC,
+ FWDInfo->RevFwdInterval,
+ (FWDInfo->SendNew) ? CHKD : UNC,
+ (FWDInfo->AllowBlocked) ? CHKD : UNC,
+ FWDInfo->MaxFBBBlockSize,
+ (FWDInfo->PersonalOnly) ? CHKD : UNC,
+ (FWDInfo->AllowCompressed) ? CHKD : UNC,
+ (FWDInfo->AllowB1) ? CHKD : UNC,
+ (FWDInfo->AllowB2) ? CHKD : UNC,
+ (FWDInfo->SendCTRLZ) ? CHKD : UNC,
+ FWDInfo->ConTimeout);
+
+ *ReplyLen = Len;
+
+}
+
+VOID SendConfigPage(char * Reply, int * ReplyLen, char * Key)
+{
+ int Len, i;
+
+ char HF[2048] = "";
+ char HT[2048] = "";
+ char HA[2048] = "";
+ char HB[2048] = "";
+ char RF[2048] = "";
+ char RT[2048] = "";
+ char RA[2048] = "";
+ char RB[2048] = "";
+ char WPTO[10000] = "";
+
+ char FBBFilters[100000] = "";
+
+
+ char * ptr = FBBFilters;
+ FBBFilter * Filter = Filters;
+
+ SetMultiStringValue(RejFrom, RF);
+ SetMultiStringValue(RejTo, RT);
+ SetMultiStringValue(RejAt, RA);
+ SetMultiStringValue(RejBID, RB);
+ SetMultiStringValue(HoldFrom, HF);
+ SetMultiStringValue(HoldTo, HT);
+ SetMultiStringValue(HoldAt, HA);
+ SetMultiStringValue(HoldBID, HB);
+ SetMultiStringValue(SendWPAddrs, WPTO);
+
+ // set up FB style fiters
+
+ ptr += sprintf(ptr,
+ "| Action | Type | From | To | @BBS | Bid | Max Size |
");
+
+ while(Filter)
+ {
+ ptr += sprintf(ptr, ""
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " |
",
+ Filter->Action, Filter->Type, Filter->From, Filter->TO, Filter->AT, Filter->BID, Filter->MaxLen);
+
+ Filter = Filter->Next;
+ }
+
+ // Add a few blank entries for input
+
+ for (i = 0; i < 5; i++)
+ {
+ ptr += sprintf(ptr, ""
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " | "
+ " |
", ' ', ' ', "", "", "", "", 0);
+ }
+
+ ptr += sprintf(ptr, "
");
+
+ Debugprintf("%d", strlen(FBBFilters));
+
+ Len = sprintf(Reply, ConfigTemplate,
+ BBSName, Key, Key, Key, Key, Key, Key, Key, Key, Key,
+ BBSName, SYSOPCall, HRoute,
+ (SendBBStoSYSOPCall) ? CHKD : UNC,
+ BBSApplNum, MaxStreams,
+ (SendSYStoSYSOPCall) ? CHKD : UNC,
+ (RefuseBulls) ? CHKD : UNC,
+ (EnableUI) ? CHKD : UNC,
+ MailForInterval,
+ (DontHoldNewUsers) ? CHKD : UNC,
+ (DefaultNoWINLINK) ? CHKD : UNC,
+ (AllowAnon) ? CHKD : UNC,
+ (DontNeedHomeBBS) ? CHKD : UNC,
+ (DontCheckFromCall) ? CHKD : UNC,
+ (UserCantKillT) ? UNC : CHKD, // Reverse logic
+ (ForwardToMe) ? CHKD : UNC,
+ (OnlyKnown) ? CHKD : UNC,
+ (reportMailEvents) ? CHKD : UNC,
+ POP3InPort, SMTPInPort, NNTPInPort,
+ (RemoteEmail) ? CHKD : UNC,
+ AMPRDomain,
+ (SendAMPRDirect) ? CHKD : UNC,
+ (ISP_Gateway_Enabled) ? CHKD : UNC,
+ MyDomain, ISPSMTPName, ISPSMTPPort, ISPEHLOName, ISPPOP3Name, ISPPOP3Port,
+ ISPAccountName, ISPAccountPass, ISPPOP3Interval,
+ (SMTPAuthNeeded) ? CHKD : UNC,
+ (SendWP) ? CHKD : UNC,
+ (FilterWPBulls) ? CHKD : UNC,
+ (SendWPType == 0) ? CHKD : UNC,
+ (SendWPType == 1) ? CHKD : UNC,
+ WPTO,
+ RF, RT, RA, RB, HF, HT, HA, HB, FBBFilters);
+
+ *ReplyLen = Len;
+}
+VOID SendHouseKeeping(char * Reply, int * ReplyLen, char * Key)
+{
+ char FromList[1000]= "", ToList[1000]= "", AtList[1000] = "";
+ char Line[80];
+ struct Override ** Call;
+
+ if (LTFROM)
+ {
+ Call = LTFROM;
+ while(Call[0])
+ {
+ sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days);
+ strcat(FromList, Line);
+ Call++;
+ }
+ }
+ if (LTTO)
+ {
+ Call = LTTO;
+ while(Call[0])
+ {
+ sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days);
+ strcat(ToList, Line);
+ Call++;
+ }
+ }
+
+ if (LTAT)
+ {
+ Call = LTAT;
+ while(Call[0])
+ {
+ sprintf(Line, "%s, %d\r\n", Call[0]->Call, Call[0]->Days);
+ strcat(AtList, Line);
+ Call++;
+ }
+ }
+
+ *ReplyLen = sprintf(Reply, HousekeepingTemplate,
+ BBSName, Key, Key, Key, Key, Key, Key, Key, Key, Key,
+ MaintTime, MaintInterval, MaxMsgno, BidLifetime, LogAge, UserLifetime,
+ (DeletetoRecycleBin) ? CHKD : UNC,
+ (SendNonDeliveryMsgs) ? CHKD : UNC,
+ (SuppressMaintEmail) ? CHKD : UNC,
+ (GenerateTrafficReport) ? CHKD : UNC,
+ PR, PUR, PF, PNF, BF, BNF, NTSD, NTSF, NTSU,
+ FromList, ToList, AtList,
+ (OverrideUnsent) ? CHKD : UNC);
+
+ return;
+
+}
+
+
+VOID SendWelcomePage(char * Reply, int * ReplyLen, char * Key)
+{
+ int Len;
+
+ Len = SendHeader(Reply, Key);
+
+ Len += sprintf(&Reply[Len], Welcome, Key, WelcomeMsg, NewWelcomeMsg, ExpertWelcomeMsg,
+ Prompt, NewPrompt, ExpertPrompt, SignoffMsg);
+ *ReplyLen = Len;
+}
+
+VOID SendFwdMainPage(char * Reply, int * RLen, char * Key)
+{
+ char ALIASES[16384];
+
+ SetMultiStringValue(AliasText, ALIASES);
+
+ *RLen = sprintf(Reply, FwdTemplate, Key, Key, BBSName,
+ Key, Key, Key, Key, Key, Key, Key, Key,
+ Key, MaxTXSize, MaxRXSize, MaxAge,
+ (WarnNoRoute) ? CHKD : UNC,
+ (Localtime) ? CHKD : UNC,
+ (SendPtoMultiple) ? CHKD : UNC,
+ ALIASES);
+}
+
+
+char TenSpaces[] = " ";
+
+VOID SendUIPage(char * Reply, int * ReplyLen, char * Key)
+{
+ int Len, i;
+
+ Len = SendHeader(Reply, Key);
+ Len += sprintf(&Reply[Len], UIHddr, Key, MailForText);
+
+ for (i = 1; i <= GetNumberofPorts(); i++)
+ {
+ char PortNo[512];
+ char PortDesc[31];
+ int n;
+
+ // Only allow UI on ax.25 ports
+
+ struct _EXTPORTDATA * PORTVEC;
+
+ PORTVEC = (struct _EXTPORTDATA * )GetPortTableEntryFromSlot(i);
+
+ if (PORTVEC->PORTCONTROL.PORTTYPE == 16) // EXTERNAL
+ if (PORTVEC->PORTCONTROL.PROTOCOL == 10) // Pactor/WINMOR
+ if (PORTVEC->PORTCONTROL.UICAPABLE == 0)
+ continue;
+
+
+ GetPortDescription(i, PortDesc);
+ n = sprintf(PortNo, "Port %2d %s", GetPortNumber(i), PortDesc);
+
+ while (PortNo[--n] == ' ');
+
+ PortNo[n + 1] = 0;
+
+ while (n++ < 38)
+ strcat(PortNo, " ");
+
+ Len += sprintf(&Reply[Len], UILine,
+ (UIEnabled[i])?CHKD:UNC, i,
+ PortNo,
+ (UIDigi[i])?UIDigi[i]:"", i,
+ (UIMF[i])?CHKD:UNC, i,
+ (UIHDDR[i])?CHKD:UNC, i,
+ (UINull[i])?CHKD:UNC, i);
+ }
+
+ Len += sprintf(&Reply[Len], UITail, Key);
+
+ *ReplyLen = Len;
+}
+
+VOID SendStatusPage(char * Reply, int * ReplyLen, char * Key)
+{
+ int Len;
+ char msg[1024];
+ CIRCUIT * conn;
+ int i,n, SYSOPMsgs = 0, HeldMsgs = 0;
+ char Name[80];
+
+ SMTPMsgs = 0;
+
+ Len = sprintf(Reply, RefreshMainPage, BBSName, BBSName, Key, Key, Key, Key, Key, Key, Key, Key);
+
+ Len += sprintf(&Reply[Len], StatusPage, Key);
+
+ for (n = 0; n < NumberofStreams; n++)
+ {
+ conn=&Connections[n];
+
+ if (!conn->Active)
+ {
+ strcpy(msg,"Idle "
+ " "
+ " \r\n");
+ }
+ else
+ {
+ {
+ if (conn->UserPointer == 0)
+ strcpy(msg,"Logging in\r\n");
+ else
+ {
+ strcpy(Name, conn->UserPointer->Name);
+ Name[9] = 0;
+
+ i=sprintf_s(msg, sizeof(msg), "%s%s%s%s%2d %5d\r\n",
+ Name,
+ &TenSpaces[strlen(Name) * 6],
+ conn->UserPointer->Call,
+ &TenSpaces[strlen(conn->UserPointer->Call) * 6],
+ conn->BPQStream,
+ conn->OutputQueueLength - conn->OutputGetPointer);
+ }
+ }
+ }
+ Len += sprintf(&Reply[Len], StatusLine, conn->BPQStream, msg);
+ }
+
+ n = 0;
+
+ for (i=1; i <= NumberofMessages; i++)
+ {
+ if (MsgHddrPtr[i]->status == 'N')
+ {
+ if (_stricmp(MsgHddrPtr[i]->to, SYSOPCall) == 0 || _stricmp(MsgHddrPtr[i]->to, "SYSOP") == 0)
+ SYSOPMsgs++;
+ else
+ if (MsgHddrPtr[i]->to[0] == 0)
+ SMTPMsgs++;
+ }
+ else
+ {
+ if (MsgHddrPtr[i]->status == 'H')
+ HeldMsgs++;
+ }
+ }
+
+ Len += sprintf(&Reply[Len], StreamEnd,
+ NumberofMessages, SYSOPMsgs, HeldMsgs, SMTPMsgs);
+
+ // If there are any active multicast transfers, display them.
+
+ Len += MulticastStatusHTML(&Reply[Len]);
+
+ Len += sprintf(&Reply[Len], StatusTail,
+ NumberofMessages, SYSOPMsgs, HeldMsgs, SMTPMsgs);
+
+ *ReplyLen = Len;
+}
+
+VOID SendFwdSelectPage(char * Reply, int * ReplyLen, char * Key)
+{
+ struct UserInfo * USER;
+ int i = 0;
+ int Len = 0;
+
+ for (USER = BBSChain; USER; USER = USER->BBSNext)
+ {
+ Len += sprintf(&Reply[Len], "%s|", USER->Call);
+ }
+
+ *ReplyLen = Len;
+}
+
+VOID SendUserSelectPage(char * Reply, int * ReplyLen, char * Key)
+{
+ struct UserInfo * USER;
+ int i = 0, n;
+ int Len = 0;
+ struct UserInfo * users[10000];
+
+ // Get array of addresses
+
+ for (n = 1; n <= NumberofUsers; n++)
+ {
+ users[i++] = UserRecPtr[n];
+ if (i > 9999) break;
+ }
+
+ qsort((void *)users, i, sizeof(void *), compare );
+
+ for (n = 0; n < NumberofUsers; n++)
+ {
+ USER = users[n];
+ Len += sprintf(&Reply[Len], "%s|", USER->Call);
+ }
+ *ReplyLen = Len;
+}
+
+int SendUserDetails(struct HTTPConnectionInfo * Session, char * Reply, char * Key)
+{
+ char SSID[16][16] = {""};
+ char ASSID[16];
+ int i, n, s, Len;
+ struct UserInfo * User = Session->User;
+ unsigned int flags = User->flags;
+ int RMSSSIDBits = Session->User->RMSSSIDBits;
+ char HiddenPass[20] = "";
+
+ int ConnectsIn;
+ int ConnectsOut;
+ int MsgsReceived;
+ int MsgsSent;
+ int MsgsRejectedIn;
+ int MsgsRejectedOut;
+ int BytesForwardedIn;
+ int BytesForwardedOut;
+// char MsgsIn[80];
+// char MsgsOut[80];
+// char BytesIn[80];
+// char BytesOut[80];
+// char RejIn[80];
+// char RejOut[80];
+
+ i = 0;
+
+ ConnectsIn = User->Total.ConnectsIn - User->Last.ConnectsIn;
+ ConnectsOut = User->Total.ConnectsOut - User->Last.ConnectsOut;
+
+ MsgsReceived = MsgsSent = MsgsRejectedIn = MsgsRejectedOut = BytesForwardedIn = BytesForwardedOut = 0;
+
+ for (n = 0; n < 4; n++)
+ {
+ MsgsReceived += User->Total.MsgsReceived[n] - User->Last.MsgsReceived[n];
+ MsgsSent += User->Total.MsgsSent[n] - User->Last.MsgsSent[n];
+ BytesForwardedIn += User->Total.BytesForwardedIn[n] - User->Last.BytesForwardedIn[n];
+ BytesForwardedOut += User->Total.BytesForwardedOut[n] - User->Last.BytesForwardedOut[n];
+ MsgsRejectedIn += User->Total.MsgsRejectedIn[n] - User->Last.MsgsRejectedIn[n];
+ MsgsRejectedOut += User->Total.MsgsRejectedOut[n] - User->Last.MsgsRejectedOut[n];
+ }
+
+
+ for (s = 0; s < 16; s++)
+ {
+ if (RMSSSIDBits & (1 << s))
+ {
+ if (s)
+ sprintf(&SSID[i++][0], "%d", s);
+ else
+ SSID[i++][0] = 0;
+ }
+ }
+
+ memset(HiddenPass, '*', strlen(User->CMSPass));
+
+ i = (flags >> 28);
+ sprintf(ASSID, "%d", i);
+
+ if (i == 0)
+ ASSID[0] = 0;
+
+ if (!UserDetailTemplate)
+ UserDetailTemplate = GetTemplateFromFile(4, "UserDetail.txt");
+
+ Len = sprintf(Reply, UserDetailTemplate, Key, User->Call,
+ (flags & F_BBS)?CHKD:UNC,
+ (flags & F_EMAIL)?CHKD:UNC,
+ (flags & F_PMS)?CHKD:UNC,
+ (flags & F_Temp_B2_BBS)?CHKD:UNC,
+ (flags & F_SYSOP)?CHKD:UNC,
+ (flags & F_POLLRMS)?CHKD:UNC,
+ (flags & F_Expert)?CHKD:UNC,
+ SSID[0], SSID[1], SSID[2], SSID[3],
+ (flags & F_Excluded)?CHKD:UNC,
+ (flags & F_HOLDMAIL)?CHKD:UNC,
+ (flags & F_SYSOP_IN_LM)?CHKD:UNC,
+ (flags & F_NOWINLINK)?CHKD:UNC,
+ (flags & F_NOBULLS)?UNC:CHKD, // Inverted flag
+ (flags & F_NTSMPS)?CHKD:UNC,
+ (flags & F_RMSREDIRECT)?CHKD:UNC,
+ (flags & F_APRSMFOR)?CHKD:UNC, ASSID,
+
+ ConnectsIn, MsgsReceived, MsgsRejectedIn,
+ ConnectsOut, MsgsSent, MsgsRejectedOut,
+ BytesForwardedIn, FormatDateAndTime((time_t)User->TimeLastConnected, FALSE),
+ BytesForwardedOut, User->lastmsg,
+ User->Name,
+ User->pass,
+ HiddenPass,
+ User->Address,
+ User->ZIP,
+ User->HomeBBS);
+
+ return Len;
+}
+
+#ifdef WIN32
+
+int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer);
+
+static char PipeFileName[] = "\\\\.\\pipe\\BPQMailWebPipe";
+
+static DWORD WINAPI InstanceThread(LPVOID lpvParam)
+
+// This routine is a thread processing function to read from and reply to a client
+// via the open pipe connection passed from the main loop. Note this allows
+// the main loop to continue executing, potentially creating more threads of
+// of this procedure to run concurrently, depending on the number of incoming
+// client connections.
+{
+ DWORD cbBytesRead = 0, cbReplyBytes = 0, cbWritten = 0;
+ BOOL fSuccess = FALSE;
+ HANDLE hPipe = NULL;
+ char Buffer[250000];
+ char OutBuffer[250000];
+ char * MsgPtr;
+ int InputLen = 0;
+ int OutputLen = 0;
+ struct HTTPConnectionInfo Session;
+ char URL[100001];
+ char * Context, * Method;
+ int n;
+
+ char * ptr;
+
+ // The thread's parameter is a handle to a pipe object instance.
+
+ hPipe = (HANDLE) lpvParam;
+
+ // First block is the HTTPConnectionInfo record, rest is request
+
+ n = ReadFile(hPipe, &Session, sizeof (struct HTTPConnectionInfo), &n, NULL);
+
+ // Get the data
+
+ fSuccess = ReadFile(hPipe, Buffer, 250000, &InputLen, NULL);
+
+ if (!fSuccess || InputLen == 0)
+ {
+ if (GetLastError() == ERROR_BROKEN_PIPE)
+ Debugprintf("InstanceThread: client disconnected.", GetLastError());
+ else
+ Debugprintf("InstanceThread ReadFile failed, GLE=%d.", GetLastError());
+
+ return 1;
+ }
+
+ Buffer[InputLen] = 0;
+
+ MsgPtr = &Buffer[0];
+
+ if (memcmp(MsgPtr, "WMRefresh", 9) == 0)
+ {
+ OutputLen = ProcessWebmailWebSock(MsgPtr, OutBuffer);
+ }
+ else
+ {
+ strcpy(URL, MsgPtr);
+
+ ptr = strstr(URL, " HTTP");
+
+ if (ptr)
+ *ptr = 0;
+
+ Method = strtok_s(URL, " ", &Context);
+
+ ProcessMailHTTPMessage(&Session, Method, Context, MsgPtr, OutBuffer, &OutputLen, InputLen);
+ }
+
+ WriteFile(hPipe, &Session, sizeof (struct HTTPConnectionInfo), &n, NULL);
+ WriteFile(hPipe, OutBuffer, OutputLen, &cbWritten, NULL);
+
+ FlushFileBuffers(hPipe);
+ DisconnectNamedPipe(hPipe);
+ CloseHandle(hPipe);
+
+ return 1;
+}
+
+static DWORD WINAPI PipeThreadProc(LPVOID lpvParam)
+{
+ BOOL fConnected = FALSE;
+ DWORD dwThreadId = 0;
+ HANDLE hPipe = INVALID_HANDLE_VALUE, hThread = NULL;
+
+// The main loop creates an instance of the named pipe and
+// then waits for a client to connect to it. When the client
+// connects, a thread is created to handle communications
+// with that client, and this loop is free to wait for the
+// next client connect request. It is an infinite loop.
+
+ for (;;)
+ {
+ hPipe = CreateNamedPipe(
+ PipeFileName, // pipe name
+ PIPE_ACCESS_DUPLEX, // read/write access
+ PIPE_TYPE_BYTE | // message type pipe
+ PIPE_WAIT, // blocking mode
+ PIPE_UNLIMITED_INSTANCES, // max. instances
+ 4096, // output buffer size
+ 4096, // input buffer size
+ 0, // client time-out
+ NULL); // default security attribute
+
+ if (hPipe == INVALID_HANDLE_VALUE)
+ {
+ Debugprintf("CreateNamedPipe failed, GLE=%d.\n", GetLastError());
+ return -1;
+ }
+
+ // Wait for the client to connect; if it succeeds,
+ // the function returns a nonzero value. If the function
+ // returns zero, GetLastError returns ERROR_PIPE_CONNECTED.
+
+ fConnected = ConnectNamedPipe(hPipe, NULL) ?
+ TRUE : (GetLastError() == ERROR_PIPE_CONNECTED);
+
+ if (fConnected)
+ {
+ // Create a thread for this client.
+
+ hThread = CreateThread(
+ NULL, // no security attribute
+ 0, // default stack size
+ InstanceThread, // thread proc
+ (LPVOID) hPipe, // thread parameter
+ 0, // not suspended
+ &dwThreadId); // returns thread ID
+
+ if (hThread == NULL)
+ {
+ Debugprintf("CreateThread failed, GLE=%d.\n", GetLastError());
+ return -1;
+ }
+ else CloseHandle(hThread);
+ }
+ else
+ // The client could not connect, so close the pipe.
+ CloseHandle(hPipe);
+ }
+
+ return 0;
+}
+
+BOOL CreatePipeThread()
+{
+ DWORD ThreadId;
+ CreateThread(NULL, 0, PipeThreadProc, 0, 0, &ThreadId);
+ return TRUE;
+}
+
+#endif
+
+char *month[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+char *dat[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
+
+VOID FormatTime(char * Time, time_t cTime)
+{
+ struct tm * TM;
+ TM = gmtime(&cTime);
+
+ sprintf(Time, "%s, %02d %s %3d %02d:%02d:%02d GMT", dat[TM->tm_wday], TM->tm_mday, month[TM->tm_mon],
+ TM->tm_year + 1900, TM->tm_hour, TM->tm_min, TM->tm_sec);
+}
+
+
+
+
+
+
+
diff --git a/mailapi.c b/mailapi.c
new file mode 100644
index 0000000..b60ec77
--- /dev/null
+++ b/mailapi.c
@@ -0,0 +1,196 @@
+// basic JASON API to BPQ Node
+
+// Authentication is via Telnet USER records.
+
+
+#define _CRT_SECURE_NO_DEPRECATE
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+
+//#include
+#include "CHeaders.h"
+#include
+#include "bpqmail.h"
+
+
+// Constants
+#define TOKEN_SIZE 32 // Length of the authentication token
+#define TOKEN_EXPIRATION 7200 // Token expiration time in seconds (2 hours)
+
+// Token data structure
+typedef struct MailToken {
+ char token[TOKEN_SIZE + 1];
+ time_t expiration_time;
+ struct UserInfo * User;
+ char Call[10];
+ struct MailToken* next;
+} MailToken;
+
+static MailToken * token_list = NULL;
+
+static int verify_token(const char* token);
+static void remove_expired_tokens();
+static int request_token(char * response);
+static void add_token_to_list(MailToken* token);
+static MailToken * find_token(const char* token);
+
+static MailToken * generate_token()
+{
+ // Generate a random authentication token
+ int i;
+
+ MailToken * token = malloc(sizeof(MailToken));
+
+ srand(time(NULL));
+
+ for (i = 0; i < TOKEN_SIZE; i++)
+ {
+ token->token[i] = 'A' + rand() % 26; // Random uppercase alphabet character
+ }
+ token->token[TOKEN_SIZE] = '\0'; // Null-terminate the token
+ token->expiration_time = time(NULL) + TOKEN_EXPIRATION; // Set token expiration time
+ add_token_to_list(token);
+ return token;
+}
+
+// Function to add the token to the token_list
+static void add_token_to_list(MailToken * token)
+{
+ if (token_list == NULL)
+ {
+ token_list = token;
+ token->next = NULL;
+ }
+ else
+ {
+ MailToken * current = token_list;
+
+ while (current->next != NULL)
+ current = current->next;
+
+ current->next = token;
+ token->next = NULL;
+ }
+}
+
+static int verify_token(const char* token)
+{
+ // Find the token in the token list
+ MailToken * existing_token = find_token(token);
+
+ if (existing_token != NULL)
+ {
+ // Check if the token has expired
+ time_t current_time = time(NULL);
+ if (current_time > existing_token->expiration_time)
+ {
+ // Token has expired, remove it from the token list
+ remove_expired_tokens();
+ return 0;
+ }
+ // Token is valid
+ return 1;
+ }
+
+ // Token doesn't exist in the token list
+ return 0;
+}
+
+static void remove_expired_tokens()
+{
+ time_t current_time = time(NULL);
+ MailToken* current_token = token_list;
+ MailToken* prev_token = NULL;
+ MailToken* next_token;
+
+ while (current_token != NULL)
+ {
+ if (current_time > current_token->expiration_time)
+ {
+ // Token has expired, remove it from the token list
+ if (prev_token == NULL)
+ {
+ token_list = current_token->next;
+ } else {
+ prev_token->next = current_token->next;
+ }
+ next_token = current_token->next;
+ free(current_token);
+ current_token = next_token;
+ } else {
+ prev_token = current_token;
+ current_token = current_token->next;
+ }
+ }
+}
+
+static MailToken * find_token(const char* token)
+{
+ MailToken * current_token = token_list;
+ while (current_token != NULL)
+ {
+ if (strcmp(current_token->token, token) == 0)
+ {
+ return current_token;
+ }
+ current_token = current_token->next;
+ }
+ return NULL;
+}
+
+static int send_http_response(char * response, const char* msg)
+{
+ return sprintf(response, "HTTP/1.1 %s\r\nContent-Length: 0\r\nConnection: close\r\n\r\n", msg);
+}
+
+
+int MailAPIProcessHTTPMessage(char * response, char * Method, char * URL, char * request, BOOL LOCAL, char *Params)
+{
+ char * pass = strlop(Params, '&');
+ int Flags = 0;
+ MailToken * Token;
+
+
+ // Check if the request is for token generation
+
+ if (strcmp(Method, "GET") != 0)
+ return send_http_response(response, "403 (Bad Method)");
+
+ if (_stricmp(URL, "/mail/api/login") == 0)
+ {
+ // user is in Params and Password in pass
+
+ struct UserInfo * User;
+ char Msg[256];
+ int n;
+
+ User = LookupCall(Params);
+
+ if (User)
+ {
+ // Check Password
+
+ if (pass[0] == 0 || strcmp(User->pass, pass) != 0 || User->flags & F_Excluded)
+ return send_http_response(response, "403 (Login Failed)");
+
+ n=sprintf_s(Msg, sizeof(Msg), "API Connect from %s", _strupr(Params));
+ WriteLogLine(NULL, '|',Msg, n, LOG_BBS);
+
+ Token = generate_token();
+ add_token_to_list(Token);
+
+ Token->User = User;
+
+ strcpy(Token->Call, Params);
+
+ // Return Token
+
+ sprintf(response, "{\"access_token\":\"%s\", \"expires_in\":%d, \"scope\":\"create\"}\r\n",
+ Token->token, TOKEN_EXPIRATION);
+
+ return strlen(response);
+
+ }
+ }
+
+ return 0;
+}
diff --git a/makefile b/makefile
index 526b241..0bd8491 100644
--- a/makefile
+++ b/makefile
@@ -13,7 +13,7 @@ OBJS = pngwtran.o pngrtran.o pngset.o pngrio.o pngwio.o pngtrans.o pngrutil.o pn
MailCommands.o MailDataDefs.o LinBPQ.o MailRouting.o MailTCP.o MBLRoutines.o md5.o Moncode.o \
NNTPRoutines.o RigControl.o TelnetV6.o WINMOR.o TNCCode.o UZ7HODrv.o WPRoutines.o \
SCSTrackeMulti.o SCSPactor.o SCSTracker.o HanksRT.o UIRoutines.o AGWAPI.o AGWMoncode.o \
- DRATS.o FreeDATA.o base64.o Events.o nodeapi.o
+ DRATS.o FreeDATA.o base64.o Events.o nodeapi.o mailapi.o
# Configuration:
diff --git a/nodeapi.c b/nodeapi.c
index 83594a2..8a5a814 100644
--- a/nodeapi.c
+++ b/nodeapi.c
@@ -274,10 +274,7 @@ int sendPortList(char * response, char * token, int Flags)
char ID[33];
char * ptr;
- Array = (char *)malloc(2048);
- ArrayLen = 2048;
-
- ArrayPtr += sprintf(&Array[ArrayPtr], "[\r\n");
+ ArrayPtr += sprintf(&response[ArrayPtr], "{\"ports\":[\r\n");
for (count = 1; count <= NUMBEROFPORTS; count++)
{
@@ -449,22 +446,14 @@ int sendPortList(char * response, char * token, int Flags)
*(ptr--) = 0;
}
- if ((ArrayPtr + 512) > ArrayLen)
- {
- ArrayLen += 2048;
- Array = (char *)realloc(Array, ArrayLen);
- }
- ArrayPtr += sprintf(&Array[ArrayPtr], " {\"ID\":\"%s\", \"Driver\":\"%s\", \"Number\":%d,\"State\":\"%s\"},\r\n",
+ ArrayPtr += sprintf(&response[ArrayPtr], " {\"ID\":\"%s\", \"Driver\":\"%s\", \"Number\":%d,\"State\":\"%s\"},\r\n",
ID, DLL, Port->PORTNUMBER, Status);
}
ArrayPtr -= 3; // remove trailing comma
+ ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}\r\n");
- ArrayPtr += sprintf(&Array[ArrayPtr], "\r\n]\r\n");
-
- sprintf(response, "%s", Array);
-
- return strlen(response);
+ return ArrayPtr;
}
/*
@@ -493,7 +482,7 @@ int sendNodeList(char * response, char * token, int Flags)
Dests = DESTS;
MaxNodes = MAXDESTS;
- ArrayPtr += sprintf(&response[ArrayPtr], "[\r\n");
+ ArrayPtr += sprintf(&response[ArrayPtr], "{\"nodes\":[\r\n");
Dests-=1;
@@ -578,7 +567,7 @@ int sendNodeList(char * response, char * token, int Flags)
}
ArrayPtr -= 3; // remove comma
- ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]");
+ ArrayPtr += sprintf(&response[ArrayPtr], "\r\n]}");
return ArrayPtr;
}