linbpq/WebMail.c

6332 lines
151 KiB
C

/*
Copyright 2001-2018 John Wiseman G8BPQ
This file is part of LinBPQ/BPQ32.
LinBPQ/BPQ32 is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
LinBPQ/BPQ32 is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with LinBPQ/BPQ32. If not, see http://www.gnu.org/licenses
*/
#define _CRT_SECURE_NO_DEPRECATE
#include "CHeaders.h"
#include "bpqmail.h"
#define MAIL
#include "httpconnectioninfo.h"
#ifdef WIN32
//#include "C:\Program Files (x86)\GnuWin32\include\iconv.h"
#else
#include <iconv.h>
#include <dirent.h>
#endif
static struct HTTPConnectionInfo * FindSession(char * Key);
int APIENTRY SessionControl(int stream, int command, int param);
int SetupNodeMenu(char * Buff);
VOID SetMultiStringValue(char ** values, char * Multi);
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 DisplayWebForm(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * FileName, char * XML, char * Reply, char * RawMessage, int RawLen);
struct HTTPConnectionInfo * AllocateWebMailSession();
VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest, int InputLen);
void ConvertTitletoUTF8(WebMailInfo * WebMail, char * Title, char * UTF8Title, int Len);
char *stristr (char *ch1, char *ch2);
char * ReadTemplate(char * FormSet, char * DirName, char * FileName);
VOID DoStandardTemplateSubsitutions(struct HTTPConnectionInfo * Session, char * txtFile);
BOOL CheckifPacket(char * Via);
int GetHTMLFormSet(char * FormSet);
void ProcessFormInput(struct HTTPConnectionInfo * Session, char * input, char * Reply, int * RLen, int InputLen);
char * WebFindPart(char ** Msg, char * Boundary, int * PartLen, char * End);
struct HTTPConnectionInfo * FindWMSession(char * Key);
int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Session, char * Alert);
char * BuildFormMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Keys[1000], char * Values[1000], int NumKeys);
char * FindXMLVariable(WebMailInfo * WebMail, char * Var);
int ReplyToFormsMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Reply, BOOL Reenter);
BOOL ParsetxtTemplate(struct HTTPConnectionInfo * Session, struct HtmlFormDir * Dir, char * FN, BOOL isReply);
VOID UpdateFormAction(char * Template, char * Key);
BOOL APIENTRY GetAPRSLatLon(double * PLat, double * PLon);
BOOL APIENTRY GetAPRSLatLonString(char * PLat, char * PLon);
void FreeWebMailFields(WebMailInfo * WebMail);
VOID BuildXMLAttachment(struct HTTPConnectionInfo * Session, char * Keys[1000], char * Values[1000], int NumKeys);
VOID SaveTemplateMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest);
VOID DownloadAttachments(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Rest);
VOID getAttachmentList(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Rest);
char * BuildB2Header(WebMailInfo * WebMail, struct MsgInfo * Msg, char ** ToCalls, int Calls);
VOID FormatTime2(char * Time, time_t cTime);
VOID ProcessSelectResponse(struct HTTPConnectionInfo * Session, char * URLParams);
VOID ProcessAskResponse(struct HTTPConnectionInfo * Session, char * URLParams);
char * CheckFile(struct HtmlFormDir * Dir, char * FN);
VOID GetPage(struct HTTPConnectionInfo * Session, char * NodeURL);
VOID SendTemplateSelectScreen(struct HTTPConnectionInfo * Session, char *URLParams, int InputLen);
BOOL isAMPRMsg(char * Addr);
char * doXMLTransparency(char * string);
Dll BOOL APIENTRY APISendAPRSMessage(char * Text, char * ToCall);
void SendMessageReadEvent(char * Call, struct MsgInfo * Msg);
void SendNewMessageEvent(char * call, struct MsgInfo * Msg);
void MQTTMessageEvent(void* message);
extern char NodeTail[];
extern char BBSName[10];
extern char LTFROMString[2048];
extern char LTTOString[2048];
extern char LTATString[2048];
UCHAR BPQDirectory[260];
int LineCount = 35; // Lines per page on message list
// Forms
struct HtmlFormDir ** HtmlFormDirs = NULL;
int FormDirCount = 0;
struct HtmlForm
{
char * FileName;
BOOL HasInitial;
BOOL HasViewer;
BOOL HasReply;
BOOL HasReplyViewer;
};
struct HtmlFormDir
{
char * FormSet;
char * DirName;
struct HtmlForm ** Forms;
int FormCount;
struct HtmlFormDir ** Dirs; // Nested Directories
int DirCount;
};
char FormDirList[4][MAX_PATH] = {"Standard_Templates", "Standard Templates", "Local_Templates"};
static char PassError[] = "<p align=center>Sorry, User or Password is invalid - please try again</p>";
static char BusyError[] = "<p align=center>Sorry, No sessions available - please try later</p>";
extern char MailSignon[];
char WebMailSignon[] = "<html><head><title>BPQ32 Mail Server Access</title></head><body background='/background.jpg'>"
"<h3 align=center>BPQ32 Mail Server %s Access</h3>"
"<h3 align=center>Please enter Callsign and Password to access WebMail</h3>"
"<form method=post action=/WebMail/Signon>"
"<table align=center bgcolor=white>"
"<tr><td>User</td><td><input type=text name=user tabindex=1 size=20 maxlength=50 /></td></tr>"
"<tr><td>Password</td><td><input type=password name=password tabindex=2 size=20 maxlength=50 /></td></tr></table>"
"<p align=center><input type=submit class='btn' value=Submit /><input type=submit class='btn' value=Cancel name=Cancel /></form>";
static char MsgInputPage[] = "<html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">"
"<title></title><script src='/WebMail/webscript.js'></script>"
"<style type=\"text/css\">"
"input.btn:active {background:black;color:white;} "
"submit.btn:active {background:black;color:white;} "
"</style>"
"</head>"
"<body background=/background.jpg onload='initialize(185)' onresize='initialize(185)'>"
"<h3 align=center>Webmail Interface - Message Input Form</h3>"
"<form align=center id=myform style=\"font-family: monospace; \" method=post action=/WebMail/EMSave\?%s enctype=multipart/form-data>"
"<div style='text-align: center;'><div style='display: inline-block;'><span style='display:block; text-align: left;'>"
"To &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input size=60 id='To' name='To' value='%s'>%s<br>"
"Subject <input size=60 id='Subj' name='Subj' value=\"%s\"> &nbsp; &nbsp; &nbsp;"
// "<button onclick='document.getElementById('getFile').click()'>Attach Files</button>"
// "<input type='file' id='getFile' name='myFile[]' multiple style='display:none'><br>"
"<label for='myfile'>Attachments </label><input type='file' name='myFile[]' multiple>"
"<br>Type &nbsp;&nbsp;&nbsp;"
"<select tabindex=1 size=1 name=Type><option value=P>P</option>"
"<option value=B>B</option><option value=T>T</option></select>"
" BID <input name=BID><br><label for='myfile2'>Header &nbsp;</label>"
"<input type='file' name='myFile2[]' style='width: 220px'>"
"<label for='myfile3'> Footer </label><input type='file' name='myFile3[]'>"
"</span></div>"
"<textarea id='main' name=Msg style='overflow:auto;'>%s</textarea><br>"
"<input name=Send value=Send type=submit class='btn'> <input name=Cancel value=Cancel type=submit class='btn'></div></form>";
static char CheckFormMsgPage[] = "<html><head><meta content=\"text/html; charset=UTF-8\" http-equiv=\"content-type\">"
"<title></title><script src='/WebMail/webscript.js'></script></head>"
"<body background=/background.jpg onload='initialize(210)' onresize='initialize(210)'>"
"<h3 align=center>Webmail Forms Interface - Check Message</h3>"
"<form align=center id=myform style=\"font-family: monospace; \"method=post action=/WebMail/FormMsgSave\?%s>"
"<div style='text-align: center;'><div style='display: inline-block;'><span style='display:block; text-align: left;'>"
"To &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input size=60 id='To' name='To' value='%s'><br>"
"CC &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input size=60 id='CC' name='CC' value='%s'><br>"
"Subject <input size=60 id='Subj' name='Subj' value='%s'>"
//"<input type='file' name='myFile' multiple>"
"<br>Type &nbsp;&nbsp;&nbsp;"
"<select tabindex=1 size=1 name=Type><option value=P %s>P</option>"
"<option value=B %s>B</option><option value=T %s>T</option></select>"
" BID <input name=BID value='%s'><br><br>"
"</span></div>"
"<textarea id='main' name=Msg style='overflow:auto;'>%s</textarea><br>"
"<input name=Send value=Send type=submit class='btn'><input name=Cancel value=Cancel type=submit class='btn'></div></form>";
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 "-filename<filemodifydate" -d "%Y-%m-%d_%H-%M-%S-%%c.%%e" *
------WebKitFormBoundaryABJaEbBWB5SuAHmq
ie Header is terminated by \r\n\r\n
Value is terminated by ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
*/
// Find End of part - ie -- Boundary + CRLF or --
char * ptr, * endptr, * saveptr;
char * Msgptr;
size_t BLen = strlen(Boundary);
size_t Partlen;
saveptr = Msgptr = ptr = *Input;
while(ptr < End) // Just in case we run off end
{
if (*ptr == '-' && *(ptr+1) == '-')
{
if (memcmp(&ptr[2], Boundary, BLen) == 0)
{
// Found Boundary
Partlen = ptr - Msgptr;
ptr += (BLen + 2); // End of Boundary
if (*ptr == '-') // Terminating Boundary
*Input = NULL;
else
*Input = ptr + 2;
// Now unpack Part to Name and Value
ptr = strstr(Msgptr, "name=");
if (ptr)
{
size_t vallen;
endptr = strstr(ptr, "\r\n\r\n"); // "/r/n/r/n
if (endptr == NULL)
return FALSE; // Malformed
vallen = Partlen - (endptr - saveptr) - 6;
// name is surrounded by ""
*(--endptr) = 0; // Termanate name
ptr += 6; // to start of name string
*Name = ptr;
endptr +=5; // to Value
endptr[vallen] = 0; // terminate to simplify string handling
*Value = endptr;
*ValLen = (int)vallen;
return TRUE;
}
}
}
ptr ++;
}
return FALSE;
}
int SaveInputValue(WebMailInfo * WebMail, char * Name, char * Value, int ValLength)
{
if (strcmp(Name, "Cancel") == 0)
return FALSE;
if (strcmp(Name, "To") == 0)
WebMail->To = _strdup(Value);
else if (strcmp(Name, "CC") == 0)
WebMail->CC = _strdup(Value);
else if (strcmp(Name, "Subj") == 0)
WebMail->Subject = _strdup(Value);
else if (strcmp(Name, "Type") == 0)
WebMail->Type = Value[0];
else if (strcmp(Name, "BID") == 0)
WebMail->BID = _strdup(Value);
else if (strcmp(Name, "Msg") == 0)
WebMail->Body = _strdup(Value);
else if (_memicmp(Name, "myFile[]", 8) == 0)
{
// Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
char * fn = strstr(Name, "filename=");
char * endfn;
if (fn)
{
fn += 10;
endfn = strchr(fn, '"');
if (endfn)
{
*endfn = 0;
if (strlen(fn))
{
WebMail->FileName[WebMail->Files] = _strdup(fn);
WebMail->FileBody[WebMail->Files] = malloc(ValLength);
memcpy(WebMail->FileBody[WebMail->Files], Value, ValLength);
WebMail->FileLen[WebMail->Files++] = ValLength;
}
}
}
}
else if (_memicmp(Name, "myFile2[]", 8) == 0)
{
// Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
char * fn = strstr(Name, "filename=");
char * endfn;
if (fn)
{
fn += 10;
endfn = strchr(fn, '"');
if (endfn)
{
*endfn = 0;
if (strlen(fn))
{
WebMail->Header = malloc(ValLength + 1);
memcpy(WebMail->Header, Value, ValLength + 1);
WebMail->HeaderLen = RemoveLF(WebMail->Header, ValLength);
}
}
}
}
else if (_memicmp(Name, "myFile3[]", 8) == 0)
{
// Get File Name from param string - myFile[]"; filename="exiftool.txt" \r\nContent-Type: text/plain
char * fn = strstr(Name, "filename=");
char * endfn;
if (fn)
{
fn += 10;
endfn = strchr(fn, '"');
if (endfn)
{
*endfn = 0;
if (strlen(fn))
{
WebMail->Footer = malloc(ValLength + 1);
memcpy(WebMail->Footer, Value, ValLength + 1);
WebMail->FooterLen = RemoveLF(WebMail->Footer, ValLength);
}
}
}
}
return TRUE;
}
struct HTTPConnectionInfo * AllocateWebMailSession()
{
int KeyVal;
struct HTTPConnectionInfo * Session, * SaveNext;
time_t NOW = time(NULL);
// First see if any session records havent been used for a while
Session = WebSessionList;
while (Session)
{
if (NOW - Session->WebMailLastUsed > 1200) // 20 Mins
{
SaveNext = Session->Next;
// Release amy malloc'ed resouces
ReleaseWebMailStruct(Session->WebMail);
memset(Session, 0, sizeof(struct HTTPConnectionInfo));
Session->Next = SaveNext;
goto UseThis;
}
Session = Session->Next;
}
Session = zalloc(sizeof(struct HTTPConnectionInfo));
if (Session == NULL)
return NULL;
if (WebSessionList)
Session->Next = WebSessionList;
WebSessionList = Session;
UseThis:
Session->WebMail = zalloc(sizeof(WebMailInfo));
KeyVal = ((rand() % 100) + 1);
KeyVal *= (int)time(NULL);
sprintf(Session->Key, "%c%08X", 'W', KeyVal);
return Session;
}
struct HTTPConnectionInfo * FindWMSession(char * Key)
{
struct HTTPConnectionInfo * Session = WebSessionList;
while (Session)
{
if (strcmp(Session->Key, Key) == 0)
{
Session->WebMailLastUsed = time(NULL);
return Session;
}
Session = Session->Next;
}
return NULL;
}
// Build list of available forms
VOID ProcessFormDir(char * FormSet, char * DirName, struct HtmlFormDir *** xxx, int * DirCount)
{
struct HtmlFormDir * FormDir;
struct HtmlFormDir ** FormDirs = *xxx;
struct HtmlForm * Form;
char Search[MAX_PATH];
int count = *DirCount;
#ifdef WIN32
HANDLE hFind = INVALID_HANDLE_VALUE;
WIN32_FIND_DATA ffd;
#else
DIR *dir;
struct dirent *entry;
char name[256];
#endif
FormDir = zalloc(sizeof (struct HtmlFormDir));
FormDir->DirName = _strdup(DirName);
FormDir->FormSet = _strdup(FormSet);
FormDirs=realloc(FormDirs, (count + 1) * sizeof(void *));
FormDirs[count++] = FormDir;
*DirCount = count;
*xxx = FormDirs;
// Scan Directory for .txt files
sprintf(Search, "%s/%s/%s/*", GetBPQDirectory(), FormSet, DirName);
// Find the first file in the directory.
#ifdef WIN32
hFind = FindFirstFile(Search, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
return;
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
char Dir[MAX_PATH];
if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
continue;
// Recurse in subdir
sprintf(Dir, "%s/%s", DirName, ffd.cFileName);
ProcessFormDir(FormSet, Dir, &FormDir->Dirs, &FormDir->DirCount);
continue;
}
// Add to list
Form = zalloc(sizeof (struct HtmlForm));
Form->FileName = _strdup(ffd.cFileName);
FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *));
FormDir->Forms[FormDir->FormCount++] = Form;
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
sprintf(Search, "%s/%s/%s", GetBPQDirectory(), FormSet, DirName);
if (!(dir = opendir(Search)))
{
Debugprintf("%s %d %d", "cant open forms dir", errno, dir);
return ;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type == DT_DIR)
{
char Dir[MAX_PATH];
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Recurse in subdir
sprintf(Dir, "%s/%s", DirName, entry->d_name);
ProcessFormDir(FormSet, Dir, &FormDir->Dirs, &FormDir->DirCount);
continue;
}
// Add to list
Form = zalloc(sizeof (struct HtmlForm));
Form->FileName = _strdup(entry->d_name);
FormDir->Forms=realloc(FormDir->Forms, (FormDir->FormCount + 1) * sizeof(void *));
FormDir->Forms[FormDir->FormCount++] = Form;
}
closedir(dir);
#endif
return;
}
int GetHTMLForms()
{
int n = 0;
while (FormDirList[n][0])
GetHTMLFormSet(FormDirList[n++]);
return 0;
}
int GetHTMLFormSet(char * FormSet)
{
int i;
#ifdef WIN32
WIN32_FIND_DATA ffd;
char szDir[MAX_PATH];
HANDLE hFind = INVALID_HANDLE_VALUE;
DWORD dwError=0;
sprintf(szDir, "%s/%s/*", BPQDirectory, FormSet);
// Find the first file in the directory.
hFind = FindFirstFile(szDir, &ffd);
if (INVALID_HANDLE_VALUE == hFind)
{
// Accept either
return 0;
}
// Scan all directories looking for file
do
{
if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0)
continue;
// Add to Directory List
ProcessFormDir(FormSet, ffd.cFileName, &HtmlFormDirs, &FormDirCount);
}
}
while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
DIR *dir;
struct dirent *entry;
char name[256];
sprintf(name, "%s/%s", BPQDirectory, FormSet);
if (!(dir = opendir(name)))
{
Debugprintf("cant open forms dir %s %d %d", name, errno, dir);
}
else
{
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type == DT_DIR)
{
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
continue;
// Add to Directory List
ProcessFormDir(FormSet, entry->d_name, &HtmlFormDirs, &FormDirCount);
}
}
closedir(dir);
}
#endif
// List for testing
return 0;
Debugprintf("%d form dirs", FormDirCount);
for (i = 0; i < FormDirCount; i++)
{
struct HtmlFormDir * Dir = HtmlFormDirs[i];
int j;
Debugprintf("%3d %s", Dir->FormCount, Dir->DirName);
for (j = 0; j < Dir->FormCount; j++)
Debugprintf(" %s", Dir->Forms[j]->FileName);
if (Dir->DirCount)
{
int k, l;
for (l = 0; l < Dir->DirCount; l++)
{
Debugprintf("Subdir %3d %s", Dir->Dirs[l]->DirCount, Dir->Dirs[l]->DirName);
for (k = 0; k < Dir->Dirs[l]->FormCount; k++)
Debugprintf(" %s", Dir->Dirs[l]->Forms[k]->FileName);
}
}
}
return 0;
}
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 SendWebMailHeader(char * Reply, char * Key, struct HTTPConnectionInfo * Session)
{
return SendWebMailHeaderEx(Reply, Key, Session, NULL);
}
int SendWebMailHeaderEx(char * Reply, char * Key, struct HTTPConnectionInfo * Session, char * Alert)
{
// Ex includes an alert string to be sent before message
struct UserInfo * User = Session->User;
char Messages[245000];
int m;
struct MsgInfo * Msg;
char * ptr = Messages;
int n = NumberofMessages; //LineCount;
char Via[64];
int Count = 0;
Messages[0] = 0;
if (Alert && Alert[0])
ptr += sprintf(Messages, "<script>alert(\"%s\");window.location.href = '/Webmail/WebMail?%s';</script>", Alert, Key);
ptr += sprintf(ptr, "%s", " # Date XX Len To @ From Subject\r\n\r\n");
for (m = LatestMsg; m >= 1; m--)
{
if (ptr > &Messages[244000])
break; // protect buffer
Msg = GetMsgFromNumber(m);
if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
continue; // Protect against corrupt messages
if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
{
char UTF8Title[4096];
char * EncodedTitle;
// List if it is the right type and in the page range we want
if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
continue;
// All Types or right Type. Check Mine Flag
if (Session->WebMailMine)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyTX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyRX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to)!= 0)
continue;
}
if (Count++ < Session->WebMailSkip)
continue;
strcpy(Via, Msg->via);
strlop(Via, '.');
// make sure title is HTML safe (no < > etc) and UTF 8 encoded
EncodedTitle = doXMLTransparency(Msg->title);
memset(UTF8Title, 0, 4096); // In case convert fails part way through
ConvertTitletoUTF8(Session->WebMail, EncodedTitle, UTF8Title, 4095);
free(EncodedTitle);
ptr += sprintf(ptr, "<a href=/WebMail/WM?%s&%d>%6d</a> %s %c%c %5d %-8s%-8s%-8s%s\r\n",
Key, Msg->number, Msg->number,
FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type,
Msg->status, Msg->length, Msg->to, Via,
Msg->from, UTF8Title);
n--;
if (n == 0)
break;
}
}
if (WebMailTemplate == NULL)
WebMailTemplate = GetTemplateFromFile(6, "WebMailPage.txt");
return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Key, Key, Key, Messages);
}
int ViewWebMailMessage(struct HTTPConnectionInfo * Session, char * Reply, int Number, BOOL DisplayHTML)
{
char * Key = Session->Key;
struct UserInfo * User = Session->User;
WebMailInfo * WebMail = Session->WebMail;
char * DisplayStyle;
char Message[200000] = "";
struct MsgInfo * Msg;
char * ptr = Message;
char * MsgBytes, * Save;
int msgLen;
char FullTo[100];
char UTF8Title[4096];
int Index;
char * crcrptr;
char DownLoad[256] = "";
DisplayStyle = "textarea"; // Prevents interpretation of html and xml
Msg = GetMsgFromNumber(Number);
if (Msg == NULL)
{
ptr += sprintf(ptr, "Message %d not found\r\n", Number);
return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Message);
}
// New Display so free any old values
FreeWebMailFields(WebMail);
WebMail->CurrentMessageIndex = Number;
if (!CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
{
ptr += sprintf(ptr, "Message %d not for you\r", Number);
return sprintf(Reply, WebMailTemplate, BBSName, User->Call, Key, Key, Key, Key, Key, Key, Key, Message);
}
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);
// make sure title is UTF 8 encoded
memset(UTF8Title, 0, 4096); // In case convert fails part way through
ConvertTitletoUTF8(Session->WebMail, Msg->title, UTF8Title, 4095);
// if a B2 message diplay B2 Header instead of a locally generated one
if ((Msg->B2Flags & B2Msg) == 0)
{
ptr += sprintf(ptr, "From: %s%s\nTo: %s\nType/Status: %c%c\nDate/Time: %s\nBid: %s\nTitle: %s\n\n",
Msg->from, Msg->emailfrom, FullTo, Msg->type, Msg->status, FormatDateAndTime((time_t)Msg->datecreated, FALSE), Msg->bid, UTF8Title);
}
MsgBytes = Save = ReadMessageFile(Number);
msgLen = Msg->length;
if (Msg->type == 'P')
Index = PMSG;
else if (Msg->type == 'B')
Index = BMSG;
else
Index = TMSG;
if (MsgBytes)
{
if (Msg->B2Flags & B2Msg)
{
char * ptr1;
// if message has attachments, display them if plain text
if (Msg->B2Flags & Attachments)
{
int BodyLen, NewLen;
int i;
char *ptr2, *attptr;
sprintf(DownLoad, "<td><a href=/WebMail/DL?%s&%d>Save Attachments</a></td>", 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, "<?xml", 4) == 0 &&
_memicmp(WebMail->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, "</html>"))
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, "</html>"))
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
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;
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));
if (_stricmp(ext, ".htm") == 0 || _stricmp(ext, ".html") == 0 || _stricmp(ext, ".css") == 0 || _stricmp(ext, ".js") == 0)
{
*RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
"Content-Type: text/css\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n%s", FileSize, TimeString, FileTimeString, MsgBytes);
}
else
{
*RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n%s", FileSize, fileBit, TimeString, FileTimeString, MsgBytes);
}
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, "<html><script>window.location.href = '/';</script>");
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[] =
"<!-- Version 6 8/11/2018 -->\r\n"
"<!DOCTYPE html> \r\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\"> \r\n"
"<head> \r\n"
"<meta http-equiv=\"content-type\" content=\"text/html; charset=UTF-8\"/> \r\n"
"<style type=\"text/css\">\r\n"
"pre {margin-left: 4px;white-space: pre} \r\n"
"#main{width:700px;position:absolute;left:0px;border:2px solid;background-color: #ffffff;}\r\n"
"</style>\r\n"
"<script src=\"/WebMail/webscript.js\"></script>\r\n"
"<script type = \"text/javascript\">\r\n"
"var ws;"
"function Init()"
"{"
" if (\"WebSocket\" in window)"
" {"
" // open a web socket. Get address from URL\r\n"
" var text = window.location.href;"
" var result = text.substring(7);"
" var myArray = result.split('/', 1);"
" ws = new WebSocket('ws://' + myArray[0] + '/WMRefresh&%s');\r\n"
" ws.onopen = function() {\r\n"
" // Web Socket is connected\r\n"
" const div = document.getElementById('main');\r\n"
" div.innerHTML = 'Websock Connected'\r\n"
" ws.send('WMRefresh&%s');"
" };\r\n"
" ws.onmessage = function (evt)"
" {"
" var received_msg = evt.data;\r\n"
" const div = document.getElementById('main');\r\n"
" div.innerHTML = received_msg\r\n"
" };"
" ws.onclose = function()"
" {"
" // websocket is closed.\r\n"
" const div = document.getElementById('main');\r\n"
" div.innerHTML = 'Websock Connection Lost';\r\n"
" };"
" initialize(120);"
" }"
" else"
" {"
" // The browser doesn't support WebSocket\r\n"
" const div = document.getElementById('main');\r\n"
" div.innerHTML = 'WebSocket not supported by your Browser - AutoRefresh not availble'\r\n"
" }"
"}"
"</script>\r\n"
"<title>WebMail</title> \r\n"
"</head>\r\n"
"<body background=/background.jpg onload=Init() onresize=initialize(120)>\r\n"
"<h3 align=center> %s Webmail Interface - User %s - Message List</h3>\r\n"
"<table align=center border=1 cellpadding=2 bgcolor=white><tr>\r\n"
"\r\n"
"<td><a href=/WebMail/WMB?%s>Bulls</a></td>\r\n"
"<td><a href=/WebMail/WMP?%s>Personal</a></td>\r\n"
"<td><a href=/WebMail/WMT?%s>NTS</a></td>\r\n"
"<td><a href=/WebMail/WMALL?%s>All Types</a></td>\r\n"
"<td><a href=/WebMail/WMMine?%s>Mine</a></td>\r\n"
"<td><a href=/WebMail/WMfromMe?%s>My Sent</a></td>\r\n"
"<td><a href=/WebMail/WMtoMe?%s>My Rxed</a></td>\r\n"
"<td><a href=/WebMail/WMAuto?%s>Auto Refresh</a></td>\r\n"
"<td><a href=\"#\" onclick=\"newmsg('%s'); return false;\">Send Message</a></td>\r\n"
"<td><a href=/WebMail/WMLogout?%s>Logout</a></td>\r\n"
"<td><a href=/>Node Menu</a></td></tr></table>\r\n"
"<br>\r\n"
"<div align=left id=main style=overflow:scroll;>Waiting for data...</div>\r\n"
"</body></html>\r\n";
sprintf(Page, WebSockPage, Key, Key ,BBSName, Session->User->Call, Key, Key, Key, Key, Key, Key, Key, Key, Key, Key);
*RLen = sprintf(Reply, "%s", Page);
return;
}
if (memcmp(NodeURL, "/WebMail/QuoteOriginal/", 15) == 0)
{
// Reply to Message
int n, len;
struct MsgInfo * Msg;
char Message[100] = "";
char Title[100];
char * MsgBytes, * Save, * NewBytes;
char * ptr;
char * ptr1, * ptr2;
char * EncodedTitle;
n = Session->WebMail->CurrentMessageIndex;
Msg = GetMsgFromNumber(n);
if (Msg == NULL)
{
sprintf(Message, "Message %d not found", n);
*RLen = sprintf(Reply, "%s", Message);
return;
}
Session->WebMail->Msg = Msg;
if (stristr(Msg->title, "Re:") == 0)
sprintf(Title, "Re:%s", Msg->title);
else
sprintf(Title, "%s", Msg->title);
MsgBytes = Save = ReadMessageFile(n);
ptr = NewBytes = malloc((Msg->length * 2) + 256);
// Copy a line at a time with "> " in front of each
ptr += sprintf(ptr, "%s", "\r\n\r\n\r\n\r\n\r\nOriginal Message\r\n\r\n> ");
ptr1 = ptr2 = MsgBytes;
len = (int)strlen(MsgBytes);
while (len-- > 0)
{
*ptr++ = *ptr1;
if (*(ptr1) == '\n')
{
*ptr++ = '>';
*ptr++ = ' ';
}
ptr1++;
}
*ptr++ = 0;
EncodedTitle = doXMLTransparency(Msg->title);
*RLen = sprintf(Reply, MsgInputPage, Key, Msg->from, "", EncodedTitle , NewBytes);
free(EncodedTitle);
free(MsgBytes);
free(NewBytes);
return;
}
if (memcmp(NodeURL, "/WebMail/Reply/", 15) == 0)
{
// Reply to Message
int n = atoi(&NodeURL[15]);
struct MsgInfo * Msg;
char Message[100] = "";
char Title[100];
char * EncodedTitle;
// Quote Original
char Button[] =
" &nbsp; &nbsp; &nbsp;<script>function myfunc(){"
"document.getElementById('myform').action = '/WebMail/QuoteOriginal' + '?%s';"
" document.getElementById('myform').submit();}</script>"
"<input type=button class='btn' onclick='myfunc()' "
"value='Include Original Msg'>";
char Temp[1024];
char ReplyAddr[128];
Msg = GetMsgFromNumber(n);
if (Msg == NULL)
{
sprintf(Message, "Message %d not found", n);
*RLen = sprintf(Reply, "%s", Message);
return;
}
Session->WebMail->Msg = Msg;
// See if the message was displayed in an HTML form with a reply template
*RLen = ReplyToFormsMessage(Session, Msg, Reply, FALSE);
// If couldn't build reply form use normal text reply
if (*RLen)
return;
sprintf(Temp, Button, Key);
if (stristr(Msg->title, "Re:") == 0)
sprintf(Title, "Re:%s", Msg->title);
else
sprintf(Title, "%s", Msg->title);
strcpy(ReplyAddr, Msg->from);
strcat(ReplyAddr, Msg->emailfrom);
EncodedTitle = doXMLTransparency(Msg->title);
*RLen = sprintf(Reply, MsgInputPage, Key, Msg->from, Temp, EncodedTitle , "");
free(EncodedTitle);
return;
}
if (strcmp(NodeURL, "/WebMail/WM") == 0)
{
// Read Message
int n = 0;
if (URLParams)
n = atoi(URLParams);
if (WebMailMsgTemplate)
free(WebMailMsgTemplate);
WebMailMsgTemplate = GetTemplateFromFile(5, "WebMailMsg.txt");
*RLen = ViewWebMailMessage(Session, Reply, n, TRUE);
return;
}
if (strcmp(NodeURL, "/WebMail/WMPrev") == 0)
{
// Read Previous Message
int m;
struct MsgInfo * Msg;
struct UserInfo * User = Session->User;
for (m = Session->WebMail->CurrentMessageIndex - 1; m >= 1; m--)
{
Msg = GetMsgFromNumber(m);
if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
continue; // Protect against corrupt messages
if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
{
// Display if it is the right type and in the page range we want
if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
continue;
// All Types or right Type. Check Mine Flag
if (Session->WebMailMine)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyTX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyRX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0)
continue;
}
*RLen = ViewWebMailMessage(Session, Reply, m, TRUE);
return;
}
}
// No More
*RLen = sprintf(Reply, "<html><script>alert(\"No More Messages\");window.location.href = '/Webmail/WebMail?%s';</script></html></script></html>", Session->Key);
return;
}
if (strcmp(NodeURL, "/WebMail/WMNext") == 0)
{
// Read Previous Message
int m;
struct MsgInfo * Msg;
struct UserInfo * User = Session->User;
for (m = Session->WebMail->CurrentMessageIndex + 1; m <= LatestMsg; m++)
{
Msg = GetMsgFromNumber(m);
if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
continue; // Protect against corrupt messages
if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
{
// Display if it is the right type and in the page range we want
if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
continue;
// All Types or right Type. Check Mine Flag
if (Session->WebMailMine)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyTX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyRX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0)
continue;
}
*RLen = ViewWebMailMessage(Session, Reply, m, TRUE);
return;
}
}
// No More
*RLen = sprintf(Reply, "<html><script>alert(\"No More Messages\");window.location.href = '/Webmail/WebMail?%s';</script></html></script></html>", Session->Key);
return;
}
if (strcmp(NodeURL, "/WebMail/DisplayText") == 0)
{
// Read Message
int n = 0;
if (URLParams)
n = atoi(URLParams);
if (WebMailMsgTemplate)
free(WebMailMsgTemplate);
WebMailMsgTemplate = GetTemplateFromFile(5, "WebMailMsg.txt");
*RLen = ViewWebMailMessage(Session, Reply, n, FALSE);
return;
}
if (memcmp(NodeURL, "/WebMail/WMDel/", 15) == 0)
{
// Kill Message
int n = atoi(&NodeURL[15]);
*RLen = KillWebMailMessage(Reply, Session->Key, Session->User, n);
return;
}
if (_stricmp(NodeURL, "/WebMail/NewMsg") == 0)
{
// Add HTML Template Button if we have any HTML Form
char Button[] =
" &nbsp; &nbsp; &nbsp;<script>function myfunc(){"
"document.getElementById('myform').action = '/WebMail/GetTemplates' + '?%s';"
" document.getElementById('myform').submit();}</script>"
"<input type=button class='btn' onclick='myfunc()' "
"value='Use Template'>";
char Temp[1024];
FreeWebMailFields(Session->WebMail); // Tidy up for new message
sprintf(Temp, Button, Key);
if (FormDirCount == 0)
*RLen = sprintf(Reply, MsgInputPage, Key, "", "", "", "");
else
*RLen = sprintf(Reply, MsgInputPage, Key, "", Temp, "", "");
return;
}
if (_memicmp(NodeURL, "/WebMail/GetPage/", 17) == 0)
{
// Read and Parse Template File
GetPage(Session, NodeURL);
return;
}
if (_memicmp(NodeURL, "/WebMail/GetList/", 17) == 0)
{
// Send Select Template Popup
char * SubDir;
int DirNo = 0;
int SubDirNo = 0;
char popup[10000];
char popuphddr[] =
"<html><body align=center background='/background.jpg'>"
"<script>function myFunction() {var x = document.getElementById(\"mySelect\").value;"
"var Key = \"%s\";"
"var param = \"toolbar=yes,location=yes,directories=yes,status=yes,menubar,=scrollbars=yes,resizable=yes,titlebar=yes,toobar=yes\";"
"window.open(\"/WebMail/GetPage/\" + x + \"?\" + Key,\"_self\",param);"
"}</script>"
"<p align=center>"
"Select Required Template from %s<br><br>"
"<select size=15 id=\"mySelect\" onclick=\"myFunction()\">"
"<option value=-1>No Page Selected";
struct HtmlFormDir * Dir;
int i;
SubDir = strlop(&NodeURL[17], ':');
DirNo = atoi(&NodeURL[17]);
if (DirNo == -1)
{
// User has gone back, then selected "No Folder Selected"
// For now just stop crash
DirNo = 0;
}
if (SubDir)
SubDirNo = atoi(SubDir);
Dir = HtmlFormDirs[DirNo];
if (SubDir)
sprintf(popup, popuphddr, Key, Dir->Dirs[SubDirNo]->DirName);
else
sprintf(popup, popuphddr, Key, Dir->DirName);
if (SubDir)
{
for (i = 0; i < Dir->Dirs[SubDirNo]->FormCount; i++)
{
char * Name = Dir->Dirs[SubDirNo]->Forms[i]->FileName;
// We only send if there is a .txt file
if (_stricmp(&Name[strlen(Name) - 4], ".txt") == 0)
sprintf(popup, "%s <option value=%d:%d,%d>%s", popup, DirNo, SubDirNo, i, Name);
}
}
else
{
for (i = 0; i < Dir->FormCount; i++)
{
char * Name = Dir->Forms[i]->FileName;
// We only send if there is a .txt file
if (_stricmp(&Name[strlen(Name) - 4], ".txt") == 0)
sprintf(popup, "%s <option value=%d,%d>%s", popup, DirNo, i, Name);
}
}
sprintf(popup, "%s</select></p>", popup);
*RLen = sprintf(Reply, "%s", popup);
return;
}
if (_stricmp(NodeURL, "/WebMail/DL") == 0)
{
getAttachmentList(Session, Reply, RLen, URLParams);
return;
}
if (_stricmp(NodeURL, "/WebMail/GetDownLoad") == 0)
{
DownloadAttachments(Session, Reply, RLen, URLParams);
return;
}
if (_stricmp(NodeURL, "/WebMail/DoSelect") == 0)
{
// User has selected item from Template <select> field
ProcessSelectResponse(Session, URLParams);
return;
}
// Unrecognised message - reset session
*RLen = sprintf(Reply, WebMailSignon, BBSName, BBSName);
}
VOID SendTemplateSelectScreen(struct HTTPConnectionInfo * Session, char *Params, int InputLen)
{
// Save any supplied message fields and Send HTML Template dropdown list
char popuphddr[] =
"<html><body align=center background='/background.jpg'>"
"<script>"
"function myFunction(val) {var x = document.getElementById(val).value;"
"var Key = \"%s\";"
"var param = \"toolbar=yes,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,titlebar=yes,toobar=yes\";"
"window.open(\"/WebMail/GetList/\" + x + \"?\" + Key,\"_self\",param);"
"}"
"</script>"
"<p align=center>"
" Select Required Template Folder from List<br><br>"
"<table border=1 cellpadding=2 bgcolor=white>"
"<tr>"
"<th>Standard Templates</th>"
"<th>Local Templates</th>"
"</tr>"
"<tr><td width=50%%><select size=15 id=\"Sel1\" onclick=\"myFunction('Sel1')\">";
char NewGroup [] =
"</select></td><td width=50%% align=center>"
"<select size=15 id=Sel2 onclick=\"myFunction('Sel2')\">";
char popup[10000];
struct HtmlFormDir * Dir;
char * LastGroup;
char * Input = strstr(Params, "\r\n\r\n"); // To end of HTML header
int i;
int MsgLen = 0;
char * Boundary;
WebMailInfo * WebMail = Session->WebMail;
Input = Params;
Boundary = initMultipartUnpack(&Input);
if (Boundary == NULL)
return; // Can't work without one
// Input points to start of part. Normally preceeded by \r\n which is Boundary Terminator. If preceeded by -- we have used last part
while(Input && Input[-1] != '-')
{
char * Name, * Value;
int ValLen;
if (unpackPart(Boundary, &Input, &Name, &Value, &ValLen, Params + InputLen) == FALSE)
{
// ReportCorrupt(WebMail);
free(Boundary);
return;
}
SaveInputValue(WebMail, Name, Value, ValLen);
}
strlop(WebMail->BID, ' ');
if (strlen(WebMail->BID) > 12)
WebMail->BID[12] = 0;
UndoTransparency(WebMail->To);
UndoTransparency(WebMail->CC);
UndoTransparency(WebMail->BID);
UndoTransparency(WebMail->Subject);
UndoTransparency(WebMail->Body);
// Save values from message when Template requested (npt sure if we need these!
WebMail->OrigTo = _strdup(WebMail->To);
WebMail->OrigSubject = _strdup(WebMail->Subject);
WebMail->OrigType = WebMail->Type;
WebMail->OrigBID = _strdup(WebMail->BID);
WebMail->OrigBody = _strdup(WebMail->Body);
// Also to active fields in case not changed by form
sprintf(popup, popuphddr, Session->Key);
LastGroup = HtmlFormDirs[0]->FormSet; // Save so we know when changes
for (i = 0; i < FormDirCount; i++)
{
int n;
Dir = HtmlFormDirs[i];
if (strcmp(LastGroup, Dir->FormSet) != 0)
{
LastGroup = Dir->FormSet;
sprintf(popup, "%s%s", popup, NewGroup);
}
sprintf(popup, "%s <option value=%d>%s", popup, i, Dir->DirName);
// Recurse any Subdirs
n = 0;
while (n < Dir->DirCount)
{
sprintf(popup, "%s <option value=%d:%d>%s", popup, i, n, Dir->Dirs[n]->DirName);
n++;
}
}
sprintf(popup, "%s</select></td></tr></table></p>", popup);
*WebMail->RLen = sprintf(WebMail->Reply, "%s", popup);
free(Boundary);
return;
}
static char WinlinkAddr[] = "WINLINK.ORG";
VOID SaveNewMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest, int InputLen)
{
int i, ReplyLen = 0;
struct MsgInfo * Msg;
FILE * hFile;
int Template=0;
char * via = NULL;
BIDRec * BIDRec;
char MsgFile[MAX_PATH];
size_t WriteLen=0;
char * HDest;
char * HDestCopy;
char * HDestRest;
char * Vptr = NULL;
char * FileList = NULL;
char Prompt[256] = "Message Saved";
char OrigTo[256];
WebMailInfo * WebMail = Session->WebMail;
struct UserInfo * user;
CIRCUIT conn;
// So we can have attachments input is now Content-Type: multipart/form-data;
char * Input;
size_t MsgLen = 0;
char * Boundary;
strcpy(conn.Callsign, Session->User->Call);
Input = MsgPtr;
Boundary = initMultipartUnpack(&Input);
if (Boundary == NULL)
return; // Can't work without one
// Input points to start of part. Normally preceeded by \r\n which is Boundary Terminator. If preceeded by -- we have used last part
while(Input && Input[-1] != '-')
{
char * Name, * Value;
int ValLen;
if (unpackPart(Boundary, &Input, &Name, &Value, &ValLen, MsgPtr + InputLen) == FALSE)
{
// ReportCorrupt(WebMail);
free(Boundary);
return;
}
if (SaveInputValue(WebMail, Name, Value, ValLen) == FALSE)
{
*RLen = sprintf(Reply, "<html><script>window.location.href = '/Webmail/WebMail?%s';</script>", Session->Key);
return;
}
}
if (WebMail->txtFileName)
{
// Processing Form Input
SaveTemplateMessage(Session, MsgPtr, Reply, RLen, Rest);
// Prevent re-entry
free(WebMail->txtFileName);
WebMail->txtFileName = NULL;
return;
}
// If we aren't using a template then all the information is in the WebMail fields, as we haven't been here before.
strlop(WebMail->BID, ' ');
if (strlen(WebMail->BID) > 12)
WebMail->BID[12] = 0;
UndoTransparency(WebMail->BID);
UndoTransparency(WebMail->To);
UndoTransparency(WebMail->Subject);
UndoTransparency(WebMail->Body);
MsgLen = strlen(WebMail->Body);
// We will need to mess about with To field. Create a copy so the original can go in B2 header if we use one
if (WebMail->To[0] == 0)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"To: Call missing!\");window.history.back();</script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
if (strlen(WebMail->To) > 255)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"To: Call too long!\");window.history.back();</script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
HDest = _strdup(WebMail->To);
if (strlen(WebMail->BID))
{
if (LookupBID(WebMail->BID))
{
// Duplicate bid
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"Duplicate BID\");window.history.back();</script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
}
if (WebMail->Type == 'B')
{
if (RefuseBulls)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"This system doesn't allow sending Bulls\");window.history.back();script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
if (Session->User->flags & F_NOBULLS)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"You are not allowed to send Bulls\");window.history.back();</script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
}
// ?? Can we just loop though the rest of the code to allow multiple dests ??
HDestCopy = HDest;
while (HDest && HDest[0])
{
HDestRest = strlop(HDest, ';');
Msg = AllocateMsgRecord();
// Set number here so they remain in sequence
Msg->number = ++LatestMsg;
MsgnotoMsg[Msg->number] = Msg;
strcpy(Msg->from, Session->User->Call);
if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0)
{
Vptr=&HDest[4];
strcpy(Msg->to, "RMS");
}
else if (_memicmp(HDest, "smtp:", 5) == 0)
{
if (ISP_Gateway_Enabled)
{
Vptr=&HDest[5];
Msg->to[0] = 0;
}
}
else if (strchr(HDest, '@'))
{
strcpy(OrigTo, HDest);
Vptr = strlop(HDest, '@');
if (Vptr)
{
// If looks like a valid email address, treat as such
if (strlen(HDest) > 6 || !CheckifPacket(Vptr))
{
// Assume Email address
Vptr = OrigTo;
if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route
strcpy(Msg->to, "RMS");
else if (ISP_Gateway_Enabled)
Msg->to[0] = 0;
else if (isAMPRMsg(OrigTo))
strcpy(Msg->to, "RMS"); // Routing will redirect it
else
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"This system doesn't allow Sending to Internet Email\");window.close();</script></html>");
FreeWebMailFields(WebMail); // We will reprocess message and attachments so reinitialise
return;
}
}
else
strcpy(Msg->to, _strupr(HDest));
}
}
else
{
// No @
if (strlen(HDest) > 6)
HDest[6] = 0;
strcpy(Msg->to, _strupr(HDest));
}
if (SendBBStoSYSOPCall)
if (_stricmp(HDest, BBSName) == 0)
strcpy(Msg->to, SYSOPCall);
if (Vptr)
{
if (strlen(Vptr) > 40)
Vptr[40] = 0;
strcpy(Msg->via, _strupr(Vptr));
}
else
{
// No via. If not local user try to add BBS
struct UserInfo * ToUser = LookupCall(Msg->to);
if (ToUser)
{
// Local User. If Home BBS is specified, use it
if (ToUser->flags & F_RMSREDIRECT)
{
// sent to Winlink
strcpy(Msg->via, WinlinkAddr);
sprintf(Prompt, "Redirecting to winlink.org\r");
}
else if (ToUser->HomeBBS[0])
{
strcpy(Msg->via, ToUser->HomeBBS);
sprintf(Prompt, "%s added from HomeBBS. Message Saved", Msg->via);
}
}
else
{
// Not local user - Check WP
WPRecP WP = LookupWP(Msg->to);
if (WP)
{
strcpy(Msg->via, WP->first_homebbs);
sprintf(Prompt, "%s added from WP", Msg->via);
}
}
}
if (strlen(WebMail->Subject) > 60)
WebMail->Subject[60] = 0;
strcpy(Msg->title, WebMail->Subject);
Msg->type = WebMail->Type;
if (Session->User->flags & F_HOLDMAIL)
{
int Length=0;
char * MailBuffer = malloc(100);
char Title[100];
Msg->status = 'H';
Length = sprintf(MailBuffer, "Message %d Held\r\n", Msg->number);
sprintf(Title, "Message %d Held - %s", Msg->number, "User has Hold Messages flag set");
SendMessageToSYSOP(Title, MailBuffer, Length);
}
else
Msg->status = 'N';
if (strlen(WebMail->BID) == 0)
sprintf(Msg->bid, "%d_%s", LatestMsg, BBSName);
else
strcpy(Msg->bid, WebMail->BID);
Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
BIDRec = AllocateBIDRecord();
strcpy(BIDRec->BID, Msg->bid);
BIDRec->mode = Msg->type;
BIDRec->u.msgno = LOWORD(Msg->number);
BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
Msg->length = (int)MsgLen + WebMail->HeaderLen + WebMail->FooterLen;
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
// BuildFormMessage(Session, Msg);
if (WebMail->Files)
{
// Send as B2
char * B2Header = BuildB2Header(WebMail, Msg, NULL, 0);
hFile = fopen(MsgFile, "wb");
if (hFile)
{
WriteLen = fwrite(B2Header, 1, strlen(B2Header), hFile);
WriteLen += fwrite(WebMail->Header, 1, WebMail->HeaderLen, hFile);
WriteLen += fwrite(WebMail->Body, 1, MsgLen, hFile);
WriteLen += fwrite(WebMail->Footer, 1, WebMail->FooterLen, hFile);
WriteLen += fwrite("\r\n", 1, 2, hFile);
for (i = 0; i < WebMail->Files; i++)
{
WriteLen += fwrite(WebMail->FileBody[i], 1, WebMail->FileLen[i], hFile);
WriteLen += fwrite("\r\n", 1, 2, hFile);
}
fclose(hFile);
free(B2Header);
Msg->length = (int)WriteLen;
}
}
else
{
hFile = fopen(MsgFile, "wb");
if (hFile)
{
WriteLen += fwrite(WebMail->Header, 1, WebMail->HeaderLen, hFile);
WriteLen += fwrite(WebMail->Body, 1, MsgLen, hFile);
WriteLen += fwrite(WebMail->Footer, 1, WebMail->FooterLen, hFile);
fclose(hFile);
}
}
MatchMessagetoBBSList(Msg, &conn);
BuildNNTPList(Msg); // Build NNTP Groups list
if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
Msg->status = '$'; // Has forwarding
if (EnableUI)
SendMsgUI(Msg);
user = LookupCall(Msg->to);
// If Event Notifications enabled report a new message event
SendNewMessageEvent(user->Call, Msg);
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(Msg);
#endif
if (user && (user->flags & F_APRSMFOR))
{
char APRS[128];
char Call[16];
int SSID = user->flags >> 28;
if (SSID)
sprintf(Call, "%s-%d", Msg->to, SSID);
else
strcpy(Call, Msg->to);
sprintf(APRS, "New BBS Message %s From %s", Msg->title, Msg->from);
APISendAPRSMessage(APRS, Call);
}
HDest = HDestRest;
}
*RLen = SendWebMailHeaderEx(Reply, Session->Key, Session, Prompt);
SaveMessageDatabase();
SaveBIDDatabase();
FreeWebMailFields(WebMail);
free(HDestCopy);
return;
}
// RMS Express Forms Support
char * GetHTMLViewerTemplate(char * FN)
{
int i, j, k, l;
// Seach list of forms for base file (without .html)
for (i = 0; i < FormDirCount; i++)
{
struct HtmlFormDir * Dir = HtmlFormDirs[i];
for (j = 0; j < Dir->FormCount; j++)
{
if (strcmp(FN, Dir->Forms[j]->FileName) == 0)
{
return CheckFile(Dir, FN);
}
}
if (Dir->DirCount)
{
for (l = 0; l < Dir->DirCount; l++)
{
struct HtmlFormDir * SDir = Dir->Dirs[l];
if (SDir->DirCount)
{
struct HtmlFormDir * SSDir = SDir->Dirs[0];
int x = 1;
}
for (k = 0; k < SDir->FormCount; k++)
{
if (_stricmp(FN, SDir->Forms[k]->FileName) == 0)
{
return CheckFile(SDir, SDir->Forms[k]->FileName);
}
}
if (SDir->DirCount)
{
struct HtmlFormDir * SSDir = SDir->Dirs[0];
int x = 1;
}
}
}
}
return NULL;
}
VOID GetReply(struct HTTPConnectionInfo * Session, char * NodeURL)
{
}
VOID GetPage(struct HTTPConnectionInfo * Session, char * NodeURL)
{
// Read the HTML Template file and do any needed substitutions
WebMailInfo * WebMail = Session->WebMail;
KeyValues * txtKey = WebMail->txtKeys;
int DirNo;
char * ptr;
int FileNo = 0;
char * SubDir;
int SubDirNo;
int i;
struct HtmlFormDir * Dir;
char * Template;
char * inptr;
char FormDir[MAX_PATH] = "";
char FN[MAX_PATH] = "";
char * InputName = NULL; // HTML to input message
char * ReplyName = NULL;
char * To = NULL;
char * CC = NULL;
char * BID = NULL;
char Type = 0;
char * Subject = NULL;
char * MsgBody = NULL;
char * varptr;
char * endptr;
size_t varlen, vallen = 0;
char val[256]=""; // replacement text
char var[100] = "\"";
char * MsgBytes;
char Submit[64];
if (NodeURL == NULL)
{
//rentry after processing <select> or <ask>
goto reEnter;
}
DirNo = atoi(&NodeURL[17]);
ptr = strchr(&NodeURL[17], ',');
Dir = HtmlFormDirs[DirNo];
SubDir = strlop(&NodeURL[17], ':');
if (SubDir)
{
SubDirNo = atoi(SubDir);
Dir = Dir->Dirs[SubDirNo];
}
sprintf(Submit, "/Webmail/Submit?%s", Session->Key);
if (ptr)
FileNo = atoi(ptr + 1);
// First we read the .txt. then get name of input .html from it
if (WebMail->txtFile)
free(WebMail->txtFile);
WebMail->txtFile = NULL;
if (WebMail->txtFileName)
free(WebMail->txtFileName);
WebMail->txtFileName = _strdup(Dir->Forms[FileNo]->FileName);
// Read the file here to simplify reentry if we do <select> or <ask> substitutions
// if Dir not specified search all for Filename
if (Dir == NULL)
{
for (i = 0; i < FormDirCount; i++)
{
int n;
Dir = HtmlFormDirs[i];
MsgBytes = CheckFile(Dir, WebMail->txtFileName);
if (MsgBytes)
goto gotFile;
// Recurse any Subdirs
n = 0;
while (n < Dir->DirCount)
{
MsgBytes = CheckFile(Dir->Dirs[n], FN);
if (MsgBytes)
{
Dir = Dir->Dirs[n];
goto gotFile;
}
n++;
}
}
return;
}
else
MsgBytes = CheckFile(Dir, WebMail->txtFileName);
gotFile:
WebMail->Dir = Dir;
if (WebMail->txtFile)
free(WebMail->txtFile);
WebMail->txtFile = MsgBytes;
reEnter:
if (ParsetxtTemplate(Session, Dir, WebMail->txtFileName, FALSE) == FALSE)
{
// Template has <select> or <ask> tags and value has been requested
return;
}
if (WebMail->InputHTMLName == NULL)
{
// This is a plain text template without HTML
if (To == NULL &&WebMail->To && WebMail->To[0])
To = WebMail->To;
else
To = "";
if (CC == NULL && WebMail->CC && WebMail->CC[0])
CC = WebMail->CC;
else
CC = "";
if (Subject == NULL && WebMail->Subject && WebMail->Subject[0])
Subject = WebMail->Subject;
else
Subject = "";
if (BID == NULL && WebMail->BID && WebMail->BID[0])
BID = WebMail->BID;
else
BID = "";
if (Type == 0 && WebMail->Type)
Type = WebMail->Type;
else
Type = 'P';
if (MsgBody == NULL)
MsgBody = "";
if (MsgBody[0] == 0 && WebMail->Body && WebMail->Body[0])
MsgBody = WebMail->Body;
*WebMail->RLen = sprintf(WebMail->Reply, CheckFormMsgPage, Session->Key, To, CC, Subject,
(Type =='P') ? "Selected" : "", (Type =='B') ? "Selected" : "", (Type =='T') ? "Selected" : "", BID, MsgBody);
return;
}
Template = CheckFile(Dir, WebMail->InputHTMLName);
if (Template == NULL)
{
*WebMail->RLen = sprintf(WebMail->Reply, "%s", "HTML Template not found");
return;
}
// I've going to update the template in situ, as I can't see a better way
// of making sure all occurances of variables in any order are substituted.
// The space allocated to Template is twice the size of the file
// to allow for insertions
// First find the Form Action string and replace with our URL. It should have
// action="http://{FormServer}:{FormPort}" but some forms have localhost:8001 instead
// Also remove the OnSubmit if it contains the standard popup about having to close browser
UpdateFormAction(Template, Session->Key);
// Search for "{var }" strings in form and replace with
// corresponding variable
// we run through the Template once for each variable
while (txtKey->Key)
{
char Key[256] = "{";
strcpy(&Key[1], &txtKey->Key[1]);
ptr = strchr(Key, '>');
if (ptr)
*ptr = '}';
inptr = Template;
varptr = stristr(inptr, Key);
while (varptr)
{
// Move the remaining message up/down the buffer to make space for substitution
varlen = strlen(Key);
if (txtKey->Value)
vallen = strlen(txtKey->Value);
else vallen = 0;
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, txtKey->Value, vallen);
inptr = endptr + 1;
varptr = stristr(inptr, Key);
}
txtKey++;
}
// Remove </body></html> from end as we add it on later
ptr = stristr(Template, "</body></html>");
if (ptr)
*ptr = 0;
*WebMail->RLen = sprintf(WebMail->Reply, "%s", Template);
free(Template);
return;
}
char * xxReadTemplate(char * FormSet, char * DirName, char *FileName)
{
int FileSize;
char * MsgBytes;
char MsgFile[265];
size_t ReadLen;
struct stat STAT;
FILE * hFile;
#ifndef WIN32
// Need to do case insensitive file search
DIR *dir;
struct dirent *entry;
char name[256];
sprintf(name, "%s/%s/%s", BPQDirectory, FormSet, DirName);
if (!(dir = opendir(name)))
{
Debugprintf("cant open forms dir %s %d %d", name, errno, dir);
return 0;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type == DT_DIR)
continue;
if (stristr(entry->d_name, FileName))
{
sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), FormSet, DirName, entry->d_name);
closedir(dir);
break;
}
}
closedir(dir);
#else
sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), FormSet, DirName, FileName);
#endif
if (stat(MsgFile, &STAT) != -1)
{
hFile = fopen(MsgFile, "rb");
if (hFile == 0)
{
MsgBytes = _strdup("File is missing");
return MsgBytes;
}
FileSize = STAT.st_size;
MsgBytes = malloc(FileSize * 2); // Allow plenty of room for template substitution
ReadLen = fread(MsgBytes, 1, FileSize, hFile);
MsgBytes[FileSize] = 0;
fclose(hFile);
return MsgBytes;
}
return NULL;
}
int ReturnRawMessage(struct UserInfo * User, struct MsgInfo * Msg, char * Key, char * Reply, char * RawMessage, int len, char * ErrorString)
{
char * ErrorMsg = malloc(len + 100);
char * ptr;
char DownLoad[256];
sprintf(DownLoad, "<td><a href=/WebMail/DL?%s&%d>Save Attachments</a></td>", Key, Msg->number);
RawMessage[strlen(RawMessage)] = '.'; // We null terminated file name
RawMessage[strlen(RawMessage)] = ' '; // We null terminated file name Len = XML - RawMessage;
RawMessage[len] = 0;
// Body seems to have cr cr lf which causes double space
ptr = strstr(RawMessage, "\r\r");
while (ptr)
{
*ptr = ' ';
ptr = strstr(ptr, "\r\r");
}
sprintf(ErrorMsg, ErrorString, RawMessage);
len = sprintf(Reply, WebMailMsgTemplate, BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, DownLoad, Key, Key, Key, "textarea", ErrorMsg, "textarea");
free(ErrorMsg);
return len;
}
char * FindXMLVariable(WebMailInfo * WebMail, char * Var)
{
KeyValues * XMLKey = &WebMail->XMLKeys[0];
while (XMLKey->Key)
{
if (_stricmp(Var, XMLKey->Key) == 0)
{
return XMLKey->Value;
}
XMLKey++;
}
return NULL;
}
BOOL ParseXML(WebMailInfo * WebMail, char * XMLOrig)
{
char * XML = _strdup(XMLOrig); // Get copy so we can mess about with it
char * ptr1, * ptr2, * ptr3;
KeyValues * XMLKeys = &WebMail->XMLKeys[0];
// Extract Fields (stuff between < and >. Ignore Whitespace between fields
ptr1 = strstr(XML, "<xml_file_version>");
while (ptr1)
{
ptr2 = strchr(++ptr1, '>');
if (ptr2 == NULL)
goto quit;
*ptr2++ = 0;
ptr3 = strstr(ptr2, "</"); // end of value string
if (ptr3 == NULL)
goto quit;
*ptr3++ = 0;
XMLKeys->Key = _strdup(ptr1);
XMLKeys->Value = _strdup(ptr2);
XMLKeys++;
ptr1 = strchr(ptr3, '<');
if (_memicmp(ptr1, "</", 2) == 0)
{
// end of a parameter block. Find start of next block
ptr1 = strchr(++ptr1, '<');
ptr1 = strchr(++ptr1, '<'); // Skip start of next block
}
}
quit:
free(XML);
return TRUE;
}
/*
?xml version="1.0"?>
<RMS_Express_Form>
<form_parameters>
<xml_file_version>1,0</xml_file_version>
<rms_express_version>6.0.16.38 Debug Build</rms_express_version>
<submission_datetime>20181022105202</submission_datetime>
<senders_callsign>G8BPQ</senders_callsign>
<grid_square></grid_square>
<display_form>Alaska_ARES_ICS213_Initial_Viewer.html</display_form>
<reply_template>Alaska_ARES_ICS213_SendReply.txt</reply_template>
</form_parameters>
<variables>
<msgto>g8bpq</msgto>
<msgcc></msgcc>
<msgsender>G8BPQ</msgsender>
<msgsubject></msgsubject>
<msgbody></msgbody>
<msgp2p>false</msgp2p>
<msgisreply>false</msgisreply>
<msgisforward>false</msgisforward>
<msgisacknowledgement>false</msgisacknowledgement>
<SeqNum>G8BPQ-1</SeqNum>
<Priority>Routine</Priority>
<HX></HX>
<OrgStation></OrgStation>
<Check></Check>
<OrgLocation>Here</OrgLocation>
<Time>11:51</Time>
<Date>2018-10-22</Date>
<Incident_Name>Test</Incident_Name>
<To_Name>John</To_Name>
<From_Name>John</From_Name>
<Subjectline>Test</Subjectline>
<DateTime>2018-10-22 11:51</DateTime>
<Message></Message>
<Approved_Name>Me</Approved_Name>
<Approved_PosTitle>Me</Approved_PosTitle>
<Submit>Submit</Submit>
</variables>
</RMS_Express_Form>
*/
char HTMLNotFoundMsg[] = " *** HTML Template for message not found - displaying raw content ***\r\n\r\n%s";
char VarNotFoundMsg[] = " *** Variable {%s} not found in message - displaying raw content ***\r\n\r\n%s";
char BadXMLMsg[] = " *** XML for Variable {%s} invalid - displaying raw content ***\r\n\r\n%s";
char BadTemplateMsg[] = " *** Template near \"%s\" invalid - displaying raw content ***\r\n\r\n%s";
int DisplayWebForm(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * FileName, char * XML, char * Reply, char * RawMessage, int RawLen)
{
WebMailInfo * WebMail = Session->WebMail;
struct UserInfo * User = Session->User;
char * Key = Session->Key;
int Len = 0;
char * Form;
char * SaveReply = Reply;
char FN[MAX_PATH] = "";
char * formptr, * varptr, * xmlptr;
char * ptr = NULL, * endptr, * xmlend;
size_t varlen, xmllen;
char var[100] = "<";
KeyValues * KeyValue;
if (ParseXML(WebMail, XML))
ptr = FindXMLVariable(WebMail, "display_form");
if (ptr == NULL) // ?? No Display Form Specified??
{
// Not found - just display as normal message
return ReturnRawMessage(User, Msg, Key, Reply, RawMessage, (int)(XML - RawMessage), HTMLNotFoundMsg);
}
strcpy(FN, ptr);
Form = GetHTMLViewerTemplate(FN);
if (Form == NULL)
{
// Not found - just display as normal message
return ReturnRawMessage(User, Msg, Key, Reply, RawMessage, (int)(XML - RawMessage), HTMLNotFoundMsg);
}
formptr = Form;
// Search for {var xxx} strings in form and replace with
// corresponding variable in xml
// Don't know why, but {MsgOriginalBody} is sent instead of {var MsgOriginalBody}
varptr = stristr(Form, "{MsgOriginalBody}");
{
char * temp, * tempsave;
char * xvar, * varsave, * ptr;
if (varptr)
{
varptr++;
endptr = strchr(varptr, '}');
varlen = endptr - varptr;
if (endptr == NULL || varlen > 99)
{
// corrupt template - display raw message
char Err[256];
varptr[20] = 0;
sprintf(Err, BadTemplateMsg, varptr - 5, "%s");
return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
}
memcpy(var + 1, varptr, varlen);
var[++varlen] = '>';
var[++varlen] = 0;
xmlptr = stristr(XML, var);
if (xmlptr)
{
xmlptr += varlen;
xmlend = strstr(xmlptr, "</");
if (xmlend == NULL)
{
// Bad XML - return error message
char Err[256];
// remove <> from var as it confuses html
var[strlen(var) -1] = 0;
sprintf(Err, BadXMLMsg, var + 1, "%s");
return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
}
xmllen = xmlend - xmlptr;
}
else
{
// Variable not found - return error message
char Err[256];
// remove <> from var as it confuses html
var[strlen(var) -1] = 0;
sprintf(Err, VarNotFoundMsg, var + 1, "%s");
return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
}
// Ok, we have the position of the variable and the substitution text.
// Copy message up to variable to Result, then copy value
// We create a copy so we can rescan later.
// We also need to replace CR or CRLF with <br>
xvar = varsave = malloc(xmllen * 2);
ptr = xmlptr;
while(ptr < xmlend)
{
while (*ptr == '\n')
ptr++;
if (*ptr == '\r')
{
*ptr++;
strcpy(xvar, "<br>");
xvar += 4;
}
else
*(xvar++) = *(ptr++);
}
*xvar = 0;
temp = tempsave = malloc(strlen(Form) + strlen(XML));
memcpy(temp, formptr, varptr - formptr - 1); // omit "{"
temp += (varptr - formptr - 1);
strcpy(temp, varsave);
temp += strlen(varsave);
free(varsave);
formptr = endptr + 1;
strcpy(temp, formptr);
strcpy(Form, tempsave);
free(tempsave);
}
}
formptr = Form;
varptr = stristr(Form, "{var ");
while (varptr)
{
varptr+= 5;
endptr = strchr(varptr, '}');
varlen = endptr - varptr;
if (endptr == NULL || varlen > 99)
{
// corrupt template - display raw message
char Err[256];
varptr[20] = 0;
sprintf(Err, BadTemplateMsg, varptr - 5, "%s");
return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
}
memcpy(var, varptr, varlen);
var[varlen] = 0;
KeyValue = &WebMail->XMLKeys[0];
while (KeyValue->Key)
{
if (_stricmp(var, KeyValue->Key) == 0)
{
xmllen = strlen(KeyValue->Value);
// Ok, we have the position of the variable and the substitution text.
// Copy message up to variable to Result, then copy value
memcpy(Reply, formptr, varptr - formptr - 5); // omit "{var "
Reply += (varptr - formptr - 5);
strcpy(Reply, KeyValue->Value);
Reply += xmllen;
break;
}
if (KeyValue->Key == NULL)
{
// Not found in XML
char Err[256];
sprintf(Err, VarNotFoundMsg, var, "%s");
return ReturnRawMessage(User, Msg, Key, SaveReply, RawMessage, (int)(XML - RawMessage), Err);
}
KeyValue++;
}
formptr = endptr + 1;
varptr = stristr(endptr, "{var ");
}
// copy remaining
// Remove </body></html> as we add it later
ptr = strstr(formptr, "</body>");
if (ptr)
*ptr = 0;
strcpy(Reply, formptr);
// Add Webmail header between <Body> and form data
ptr = stristr(SaveReply, "<body");
if (ptr)
{
ptr = strchr(ptr, '>');
if (ptr)
{
char * temp = malloc(strlen(SaveReply) + 1000);
size_t len = ++ptr - SaveReply;
memcpy(temp, SaveReply, len);
sprintf(&temp[len],
"<script>function Reply(Num, Key)"
"{"
"var param = \"toolbar=yes,location=yes,directories=yes,status=yes,menubar=yes,scrollbars=yes,resizable=yes,titlebar=yes,toobar=yes\";"
"window.open(\"/WebMail/Reply/\" + Num + \"?\" + Key,\"_self\",param);"
"}</script>"
"<h3 align=center> %s Webmail Interface - User %s - Message %d</h3>"
"<table align=center border=1 cellpadding=2 bgcolor=white><tr>"
"<td><a href=\"#\" onclick=\"Reply('%d' ,'%s'); return false;\">Reply</a></td>"
"<td><a href=/WebMail/WMDel/%d?%s>Kill Message</a></td>"
"<td><a href=/WebMail/DisplayText?%s&%d>Display as Text</a></td>"
"<td><a href=/WebMail/WMNext?%s>Next</a></td>"
"<td><a href=/WebMail/WMPrev?%s>Previous</a></td>"
"<td><a href=/WebMail/WMSame?%s>Back to List</a></td>"
"</tr></table>", BBSName, User->Call, Msg->number, Msg->number, Key, Msg->number, Key, Key, Msg->number, Key, Key, Key);
strcat(temp, ptr);
strcpy(SaveReply, temp);
free(temp);
}
}
if (Form)
free(Form);
return (int)strlen(SaveReply);
}
char * BuildB2Header(WebMailInfo * WebMail, struct MsgInfo * Msg, char ** ToCalls, int Calls)
{
// Create B2 Header
char * NewMsg = malloc(100000);
char * SaveMsg = NewMsg;
char DateString[80];
struct tm * tm;
int n;
char Type[16] = "Private";
// Get Type
if (Msg->type == 'B')
strcpy(Type, "Bulletin");
else if (Msg->type == 'T')
strcpy(Type, "Traffic");
tm = gmtime((time_t *)&Msg->datecreated);
sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
NewMsg += sprintf(NewMsg,
"MID: %s\r\n"
"Date: %s\r\n"
"Type: %s\r\n"
"From: %s\r\n",
Msg->bid, DateString, Type, Msg->from);
if (ToCalls)
{
int i;
for (i = 0; i < Calls; i++)
NewMsg += sprintf(NewMsg, "To: %s\r\n", ToCalls[i]);
}
else
{
NewMsg += sprintf(NewMsg, "To: %s\r\n",
WebMail->To);
}
if (WebMail->CC && WebMail->CC[0])
NewMsg += sprintf(NewMsg, "CC: %s\r\n", WebMail->CC);
NewMsg += sprintf(NewMsg,
"Subject: %s\r\n"
"Mbo: %s\r\n",
Msg->title, BBSName);
NewMsg += sprintf(NewMsg, "Body: %d\r\n", (int)strlen(WebMail->Body) + WebMail->HeaderLen + WebMail->FooterLen);
Msg->B2Flags = B2Msg;
if (WebMail->XML)
{
Msg->B2Flags |= Attachments;
NewMsg += sprintf(NewMsg, "File: %d %s\r\n",
WebMail->XMLLen, WebMail->XMLName);
}
for (n = 0; n < WebMail->Files; n++)
{
Msg->B2Flags |= Attachments;
NewMsg += sprintf(NewMsg, "File: %d %s\r\n",
WebMail->FileLen[n], WebMail->FileName[n]);
}
NewMsg += sprintf(NewMsg, "\r\n"); // Blank Line to end header
return SaveMsg;
}
VOID WriteOneRecipient(struct MsgInfo * Msg, WebMailInfo * WebMail, int MsgLen, char ** ToCalls, int Calls, char * BID)
{
FILE * hFile;
char * via = NULL;
BIDRec * BIDRec;
char MsgFile[MAX_PATH];
size_t WriteLen=0;
char * B2Header;
if (strlen(WebMail->Subject) > 60)
WebMail->Subject[60] = 0;
strcpy(Msg->title, WebMail->Subject);
if (strlen(BID) == 0)
sprintf_s(BID, 32, "%d_%s", LatestMsg, BBSName);
strcpy(Msg->bid, BID);
Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
BIDRec = AllocateBIDRecord();
strcpy(BIDRec->BID, Msg->bid);
BIDRec->mode = Msg->type;
BIDRec->u.msgno = LOWORD(Msg->number);
BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
Msg->length = MsgLen;
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
// We write a B2 Header, Body and XML attachment if present
B2Header = BuildB2Header(WebMail, Msg, ToCalls, Calls);
hFile = fopen(MsgFile, "wb");
if (hFile)
{
int i;
WriteLen = fwrite(B2Header, 1, strlen(B2Header), hFile);
WriteLen += fwrite(WebMail->Body, 1, Msg->length, hFile);
WriteLen += fwrite("\r\n", 1, 2, hFile);
if (WebMail->XML)
{
WriteLen += fwrite(WebMail->XML, 1, WebMail->XMLLen, hFile);
WriteLen += fwrite("\r\n", 1, 2, hFile);
}
// Do any attachments
for (i = 0; i < WebMail->Files; i++)
{
WriteLen += fwrite(WebMail->FileBody[i], 1, WebMail->FileLen[i], hFile);
WriteLen += fwrite("\r\n", 1, 2, hFile);
}
fclose(hFile);
}
free(B2Header);
Msg->length = (int)WriteLen;
MatchMessagetoBBSList(Msg, 0);
if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
Msg->status = '$'; // Has forwarding
BuildNNTPList(Msg); // Build NNTP Groups list
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(Msg);
#endif
}
VOID SaveTemplateMessage(struct HTTPConnectionInfo * Session, char * MsgPtr, char * Reply, int * RLen, char * Rest)
{
int ReplyLen = 0;
struct MsgInfo * Msg;
char * ptr, *input, *context;
size_t MsgLen;
char Type;
char * via = NULL;
char BID[32];
size_t WriteLen=0;
char * Body = NULL;
char * To = NULL;
char * CC = NULL;
char * HDest = NULL;
char * Title = NULL;
char * Vptr = NULL;
char * Context;
char Prompt[256] = "Message Saved";
char OrigTo[256];
WebMailInfo * WebMail = Session->WebMail;
BOOL SendMsg = FALSE;
BOOL SendReply = FALSE;
char * RMSTo[1000] = {NULL}; // Winlink addressees
char * PKTT0[1000] = {NULL}; // Packet addressees
__int32 Recipients = 0;
__int32 RMSMsgs = 0, BBSMsgs = 0;
input = strstr(MsgPtr, "\r\n\r\n"); // End of headers
if (input == NULL)
return;
if (strstr(input, "Cancel=Cancel"))
{
*RLen = sprintf(Reply, "<html><script>window.location.href = '/Webmail/WebMail?%s';</script>", Session->Key);
return;
}
if (WebMail->txtFileName == NULL)
{
// No template, so user must have used back button
*RLen = sprintf(Reply, "<html><script>alert(\"Template missing. Was back Button used? \");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
return;
}
ptr = strtok_s(input + 4, "&", &Context);
while (ptr)
{
char * val = strlop(ptr, '=');
if (strcmp(ptr, "To") == 0)
HDest = To = val;
else if (strcmp(ptr, "CC") == 0)
CC = val;
else if (strcmp(ptr, "Subj") == 0)
Title = val;
else if (strcmp(ptr, "Type") == 0)
Type = val[0];
else if (strcmp(ptr, "BID") == 0)
strcpy(BID, val);
else if (strcmp(ptr, "Msg") == 0)
Body = _strdup(val);
ptr = strtok_s(NULL, "&", &Context);
}
strlop(BID, ' ');
if (strlen(BID) > 12)
BID[12] = 0;
UndoTransparency(To);
UndoTransparency(CC);
UndoTransparency(BID);
UndoTransparency(HDest);
UndoTransparency(Title);
UndoTransparency(Body);
MsgLen = strlen(Body);
// The user could have changed any of the input fields.
if (To && To[0])
{
free (WebMail->To);
WebMail->To = _strdup(To);
}
if (CC && CC[0])
{
free (WebMail->CC);
WebMail->CC = _strdup(CC);
}
if (Title && Title[0])
{
free (WebMail->Subject);
WebMail->Subject = _strdup(Title);
}
if (Body && Body[0])
{
free (WebMail->Body);
WebMail->Body = _strdup(Body);
}
// We will put the supplied address in the B2 header
// We may need to change the HDest to make sure message
// is delivered to Internet or Packet as requested
if (HDest == NULL || HDest[0] == 0)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"To: Call Missing\");window.history.back();</script></html>");
return;
}
// Multiple TO fields could be more than 255 bytes long
// if (strlen(HDest) > 255)
// {
// *RLen = sprintf(Reply, "%s", "<html><script>alert(\"To: Call too long!\");window.history.back();</script></html>");
// return;
// }
if (strlen(BID))
{
if (LookupBID(BID))
{
// Duplicate bid
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"Duplicate BID\");window.history.back();</script></html>");
return;
}
}
if (Type == 'B')
{
if (RefuseBulls)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"This system doesn't allow sending Bulls\");window.history.back();script></html>");
return;
}
if (Session->User->flags & F_NOBULLS)
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"You are not allowed to send Bulls\");window.history.back();</script></html>");
return;
}
}
// We should be able to handle multiple recipients, with all Winlink addresses sent in one message and
// multiple copies for packet addressess. For Winlink we should use multiple To@ lines in B2 Header
ptr = strtok_s(HDest, " ;", &context);
while (ptr && ptr[0])
{
int Winlink = 0;
int AMPR = 0;
char * dest = zalloc(256);
char * via = NULL;
strcpy(dest, ptr);
// See if packet or Winlink
// If Type=Winlink specified send plain call as @winlink.org
if (strchr(dest, '@') == 0 && WebMail->Winlink)
strcat(dest, "@winlink.org");
if (_memicmp(dest, "rms:", 4) == 0 || _memicmp(dest, "rms/", 4) == 0)
{
memcpy(dest, &dest[4], strlen(dest));
Winlink = 1;
RMSTo[RMSMsgs++] = dest;
ptr = strtok_s(NULL, " ;", &context);
continue;
}
else if (_memicmp(dest, "smtp:", 5) == 0)
{
if (ISP_Gateway_Enabled)
{
via = &dest[5];
dest[0] = 0;
}
}
else if (strchr(dest, '@'))
{
strcpy(OrigTo, dest);
via = strlop(dest, '@');
if (via)
{
// If looks like a valid email address, treat as such
if (strlen(via) > 6 || !CheckifPacket(via))
{
// Assume Email address. See if to send via RMS or SMTP
if (isAMPRMsg(OrigTo))
{
dest[strlen(dest)] = '@'; // Put back together
memmove(&dest[1], dest, strlen(dest));
dest[0] = 0;
via = &dest[1];
AMPR = 1;
}
else if (FindRMS() || strchr(via, '!')) // have RMS or source route
{
dest[strlen(dest)] = '@'; // Put back together
Winlink = 1;
RMSTo[RMSMsgs++] = dest;
ptr = strtok_s(NULL, " ;", &context);
continue;
}
else if (ISP_Gateway_Enabled)
{
dest[strlen(dest)] = '@'; // Put back together
memmove(dest, &dest[1], strlen(dest));
dest[0] = 0;
}
else
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"This system doesn't allow Sending to Internet Email\");window.close();</script></html>");
return;
}
}
}
}
else
{
// No @
if (strlen(dest) > 6)
dest[6] = 0;
}
// This isn't an RMS Message, so can queue now
Msg = AllocateMsgRecord();
// Set number here so they remain in sequence
Msg->number = ++LatestMsg;
MsgnotoMsg[Msg->number] = Msg;
strcpy(Msg->title, WebMail->Subject);
Msg->type = Type;
Msg->status = 'N';
strcpy(Msg->from, Session->User->Call);
strcpy(Msg->to, _strupr(dest));
if (SendBBStoSYSOPCall)
if (_stricmp(dest, BBSName) == 0)
strcpy(Msg->to, SYSOPCall);
if (via)
{
if (strlen(via) > 40)
via[40] = 0;
strcpy(Msg->via, _strupr(via));
}
else
{
// No via. If not local user try to add BBS
struct UserInfo * ToUser = LookupCall(Msg->to);
if (ToUser)
{
// Local User. If Home BBS is specified, use it
if (ToUser->flags & F_RMSREDIRECT)
{
// sent to Winlink
strcpy(Msg->via, WinlinkAddr);
sprintf(Prompt, "Redirecting to winlink.org\r");
}
else if (ToUser->HomeBBS[0])
{
strcpy(Msg->via, ToUser->HomeBBS);
sprintf(Prompt, "%s added from HomeBBS. Message Saved", Msg->via);
}
}
else
{
// Not local user - Check WP
WPRecP WP = LookupWP(Msg->to);
if (WP)
{
strcpy(Msg->via, WP->first_homebbs);
sprintf(Prompt, "%s added from WP", Msg->via);
}
}
}
WriteOneRecipient(Msg, WebMail, MsgLen, NULL, 0, BID);
ptr = strtok_s(NULL, " ;", &context);
free(dest);
BID[0] = 0; // Can't use more than once
}
if (RMSMsgs)
{
// Write one message to all Winlink addresses
int i;
Msg = AllocateMsgRecord();
// Set number here so they remain in sequence
Msg->number = ++LatestMsg;
MsgnotoMsg[Msg->number] = Msg;
strcpy(Msg->title, WebMail->Subject);
Msg->type = Type;
Msg->status = 'N';
strcpy(Msg->from, Session->User->Call);
strcpy(Msg->to, "RMS");
WriteOneRecipient(Msg, WebMail, MsgLen, RMSTo, RMSMsgs, BID);
for (i = 0; i < RMSMsgs; i++)
free(RMSTo[i]);
}
SaveMessageDatabase();
SaveBIDDatabase();
*RLen = SendWebMailHeaderEx(Reply, Session->Key, Session, Prompt);
FreeWebMailFields(WebMail);
return;
}
VOID DoStandardTemplateSubsitutions(struct HTTPConnectionInfo * Session, char * txtFile)
{
WebMailInfo * WebMail = Session->WebMail;
struct UserInfo * User = Session->User;
KeyValues * txtKey = WebMail->txtKeys;
char * inptr, * varptr, * endptr;
int varlen, vallen;
while (txtKey->Key != NULL)
{
inptr = WebMail->txtFile;
varptr = stristr(inptr, txtKey->Key);
while (varptr)
{
// Move the remaining message up/down the buffer to make space for substitution
varlen = (int)strlen(txtKey->Key);
if (txtKey->Value)
vallen = (int)strlen(txtKey->Value);
else
vallen = 0;
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, txtKey->Value, vallen);
inptr = endptr + 1;
varptr = stristr(inptr, txtKey->Key);
}
txtKey++;
}
}
VOID BuildMessageFromHTMLInput(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Keys[1000], char * Values[1000], int NumKeys)
{
int ReplyLen = 0;
struct MsgInfo * Msg;
int MsgLen;
FILE * hFile;
char Type = 'P';
BIDRec * BIDRec;
char * MailBuffer;
char MsgFile[MAX_PATH];
int WriteLen=0;
char Prompt[256] = "Message Saved";
char OrigTo[256];
WebMailInfo * WebMail = Session->WebMail;
char * HDest = _strdup(WebMail->To);
char * Vptr = NULL;
char BID[16] = "";
/// if (strlen(HDest) > 255)
/// {
// *RLen = sprintf(Reply, "%s", "<html><script>alert(\"To: Call too long!\");</script></html>");
// return;
// }
MsgLen = (int)strlen(WebMail->Body);
Msg = AllocateMsgRecord();
// Set number here so they remain in sequence
Msg->number = ++LatestMsg;
MsgnotoMsg[Msg->number] = Msg;
strcpy(Msg->from, Session->User->Call);
if (_memicmp(HDest, "rms:", 4) == 0 || _memicmp(HDest, "rms/", 4) == 0)
{
Vptr=&HDest[4];
strcpy(Msg->to, "RMS");
}
else if (_memicmp(HDest, "smtp:", 5) == 0)
{
if (ISP_Gateway_Enabled)
{
Vptr=&HDest[5];
Msg->to[0] = 0;
}
}
else if (strchr(HDest, '@'))
{
strcpy(OrigTo, HDest);
Vptr = strlop(HDest, '@');
if (Vptr)
{
// If looks like a valid email address, treat as such
if (strlen(HDest) > 6 || !CheckifPacket(Vptr))
{
// Assume Email address
Vptr = OrigTo;
if (FindRMS() || strchr(Vptr, '!')) // have RMS or source route
strcpy(Msg->to, "RMS");
else if (ISP_Gateway_Enabled)
Msg->to[0] = 0;
else if (isAMPRMsg(OrigTo))
strcpy(Msg->to, "RMS"); // Routing will redirect it
else
{
*RLen = sprintf(Reply, "%s", "<html><script>alert(\"This system doesn't allow Sending to Internet Email\");window.close();</script></html>");
return;
}
}
}
}
else
{
if (strlen(HDest) > 6)
HDest[6] = 0;
strcpy(Msg->to, _strupr(HDest));
}
if (SendBBStoSYSOPCall)
if (_stricmp(HDest, BBSName) == 0)
strcpy(Msg->to, SYSOPCall);
if (Vptr)
{
if (strlen(Vptr) > 40)
Vptr[40] = 0;
strcpy(Msg->via, _strupr(Vptr));
}
else
{
// No via. If not local user try to add BBS
struct UserInfo * ToUser = LookupCall(Msg->to);
if (ToUser)
{
// Local User. If Home BBS is specified, use it
if (ToUser->flags & F_RMSREDIRECT)
{
// sent to Winlink
strcpy(Msg->via, WinlinkAddr);
sprintf(Prompt, "Redirecting to winlink.org\r");
}
else if (ToUser->HomeBBS[0])
{
strcpy(Msg->via, ToUser->HomeBBS);
sprintf(Prompt, "%s added from HomeBBS", Msg->via);
}
}
else
{
// Not local user - Check WP
WPRecP WP = LookupWP(Msg->to);
if (WP)
{
strcpy(Msg->via, WP->first_homebbs);
sprintf(Prompt, "%s added from WP", Msg->via);
}
}
}
if (strlen(WebMail->Subject) > 60)
WebMail->Subject[60] = 0;
strcpy(Msg->title, WebMail->Subject);
Msg->type = Type;
Msg->status = 'N';
if (strlen(BID) == 0)
sprintf_s(BID, sizeof(BID), "%d_%s", LatestMsg, BBSName);
strcpy(Msg->bid, BID);
Msg->datereceived = Msg->datechanged = Msg->datecreated = time(NULL);
BIDRec = AllocateBIDRecord();
strcpy(BIDRec->BID, Msg->bid);
BIDRec->mode = Msg->type;
BIDRec->u.msgno = LOWORD(Msg->number);
BIDRec->u.timestamp = LOWORD(time(NULL)/86400);
MailBuffer = malloc(MsgLen + 2000); // Allow for a B2 Header if attachments
Msg->length = MsgLen;
BuildFormMessage(Session, Msg, Keys, Values, NumKeys);
sprintf_s(MsgFile, sizeof(MsgFile), "%s/m_%06d.mes", MailDir, Msg->number);
hFile = fopen(MsgFile, "wb");
if (hFile)
{
WriteLen = (int)fwrite(WebMail->Body, 1, Msg->length, hFile);
fclose(hFile);
}
free(WebMail->Body);
free(HDest);
WebMail->Body = NULL;
MatchMessagetoBBSList(Msg, 0);
if (Msg->status != 'H' && Msg->type == 'B' && memcmp(Msg->fbbs, zeros, NBMASK) != 0)
Msg->status = '$'; // Has forwarding
BuildNNTPList(Msg); // Build NNTP Groups list
#ifndef NOMQTT
if (MQTT)
MQTTMessageEvent(Msg);
#endif
SaveMessageDatabase();
SaveBIDDatabase();
*RLen = sprintf(Reply, "<html><script>alert(\"%s\");window.close();</script></html>", Prompt);
return;
}
void ProcessFormInput(struct HTTPConnectionInfo * Session, char * input, char * Reply, int * RLen, int InputLen)
{
// If there is no display html defined place data in a normal
// input window, else build the Message body and XML attachment and send
// I now think it is better to put data in a normal input window
// even if there is a display form so user can view it before submission
WebMailInfo * WebMail = Session->WebMail;
char * info = strstr(input, "\r\n\r\n"); // To end of HTML header
// look through header for Content-Type line, and if multipart
// find boundary string.
char * ptr, * saveptr, * ptr1, * ptr2, * inptr;
char Boundary[1000];
BOOL Multipart = FALSE;
int Partlen;
char ** Body = &info;
int i;
char * Keys[1000];
char * Values[1000];
char * saveForfree[1000];
int NumKeys = 0;
char * varptr;
char * endptr;
int varlen, vallen = 0;
char *crcrptr;
if (WebMail->txtFile == NULL)
{
// No template, so user must have used back button
*RLen = sprintf(Reply, "<html><script>alert(\"Template missing. Was back Button used? \");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
return;
}
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
}
// Content-Type: multipart/mixed;
// boundary="----=_NextPart_000_025B_01CAA004.84449180"
// 7.2.2 The Multipart/mixed (primary) subtype
// 7.2.3 The Multipart/alternative subtype
if (_memicmp(ptr, "Content-Type: ", 14) == 0)
{
char Line[1000] = "";
char lcLine[1000] = "";
char * ptr3;
memcpy(Line, &ptr[14], ptr2-ptr-14);
memcpy(lcLine, &ptr[14], ptr2-ptr-14);
_strlwr(lcLine);
if (_memicmp(Line, "Multipart/", 10) == 0)
{
Multipart = TRUE;
ptr3 = strstr(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;
}
else
return; // Can't do anything without a boundary ??
}
}
ptr = ptr2;
ptr++;
}
if (info == NULL)
return; // Wot!
// Extract the Key/Value pairs from input data
saveptr = ptr = WebFindPart(Body, Boundary, &Partlen, input + InputLen);
if (ptr == NULL)
return; // Couldn't find separator
// Now extract fields
while (ptr)
{
char * endptr;
char * val;
// Debugprintf(ptr);
// Format seems to be
//Content-Disposition: form-data; name="FieldName"
// crlf crlf
// field value
// crlf crlf
// No, is actually
// ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
// Content-Disposition: form-data; name="State"
//
// UK
// ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
// ie Value is terminated by ------WebKitFormBoundary7XHZ1i7Jc8tOZJbw
// But FindPart has returned length, so can use that
// Be aware that Part and PartLen include the CRLF which is actually part of the Boundary string so should be removed.
ptr = strstr(ptr, "name=");
if (ptr)
{
endptr = strstr(ptr, "\"\r\n\r\n"); // "/r/n/r/n
if (endptr)
{
*endptr = 0;
ptr += 6; // to start of name string
val = endptr + 5;
// val was Null Terminated by FindPart so can just use it. This assumes all fields are text,
// which I think is safe enough here.
saveptr[Partlen - 2] = 0;
// Now have key value pair
Keys[NumKeys] = ptr;
Values[NumKeys] = val;
saveForfree[NumKeys++] = saveptr; // so we can free() when finished with it
}
else
free(saveptr);
}
else
free(saveptr);
saveptr = ptr = WebFindPart(Body, Boundary, &Partlen, input + InputLen);
}
if (info == NULL)
return; // Wot!
info += 4;
// It looks like some standard variables can be used in <var subsitutions as well as fields from form. Put on end,
// so fields from form have priority
saveForfree[NumKeys] = 0; // flag end of malloced items
Keys[NumKeys] = "MsgTo";
Values[NumKeys++] = "";
Keys[NumKeys] = "MsgCc";
Values[NumKeys++] = "";
Keys[NumKeys] = "MsgSender";
Values[NumKeys++] = Session->User->Call;
Keys[NumKeys] = "MsgSubject";
Values[NumKeys++] = "";
Keys[NumKeys] = "MsgBody";
// if (WebMail->OrigBody)
// txtKey++->Value = _strdup(WebMail->OrigBody);
// else
Values[NumKeys++] = "";
Keys[NumKeys] = _strdup("MsgP2P");
Values[NumKeys++] = _strdup("");
Keys[NumKeys] = _strdup("MsgIsReply");
if (WebMail->isReply)
Values[NumKeys++] = "True";
else
Values[NumKeys++] = "True";
Keys[NumKeys] = "MsgIsForward";
Values[NumKeys++] = "False";
Keys[NumKeys] = "MsgIsAcknowledgement";
Values[NumKeys++] = "False";
// Update Template with variables from the form
// I've going to update the template in situ, as I can't see a better way
// of making sure all occurances of variables in any order are substituted.
// The space allocated to Template is twice the size of the file
// to allow for insertions
inptr = WebMail->txtFile;
// Search for "<var>" strings in form and replace with
// corresponding variable
// we run through the Template once for each variable
i = 0;
while (i < NumKeys)
{
char Key[256];
sprintf(Key, "<var %s>", Keys[i]);
inptr = WebMail->txtFile;
varptr = stristr(inptr, Key);
while (varptr)
{
// Move the remaining message up/down the buffer to make space for substitution
varlen = (int)strlen(Key);
vallen = (int)strlen(Values[i]);
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, Values[i], vallen);
inptr = endptr + 1;
varptr = stristr(inptr, Key);
}
i++;
}
// We need to look for To:, CC: and Subject lines, and remove any other
// Var: lines. Use everything following Msg: as the plain text body
// Find start of Message body
ptr = WebMail->txtFile;
ptr1 = strchr(ptr, '\r');
while (ptr1)
{
if (_memicmp(ptr, "Msg:", 4) == 0)
{
// Rest is message body. <var> substitutions have been done
if (WebMail->Body)
free(WebMail->Body);
WebMail->Body = _strdup(ptr + 4); // Remove Msg:
break;
}
// Can now terminate lines
*ptr1++ = 0;
while (*ptr1 == '\r' || *ptr1 == '\n')
*ptr1++ = 0;
if (_memicmp(ptr, "To:", 3) == 0)
{
if (strlen(ptr) > 5)
WebMail->To = _strdup(&ptr[3]);
}
else if (_memicmp(ptr, "CC:", 3) == 0)
{
if (strlen(ptr) > 5)
WebMail->CC = _strdup(&ptr[3]);
}
else if (_memicmp(ptr, "Subj:", 5) == 0)
{
if (ptr[5] == ' ') // May have space after :
ptr++;
if (strlen(ptr) > 6)
WebMail->Subject = _strdup(&ptr[5]);
}
else if (_memicmp(ptr, "Subject:", 8) == 0)
{
if (ptr[8] == ' ')
ptr++;
if (strlen(ptr) > 9)
WebMail->Subject = _strdup(&ptr[8]);
}
ptr = ptr1;
ptr1 = strchr(ptr, '\r');
}
if (WebMail->Subject == NULL)
WebMail->Subject = _strdup("");
if (WebMail->To == NULL)
WebMail->To = _strdup("");
if (WebMail->CC == NULL)
WebMail->CC = _strdup("");
// Replace var in Subject
if (_memicmp(WebMail->Subject, "<var ", 5) == 0)
{
WebMail->Subject = realloc(WebMail->Subject, 512); // Plenty of space
i = 0;
while (i < NumKeys)
{
char Key[256];
sprintf(Key, "<var %s>", Keys[i]);
inptr = WebMail->Subject;
varptr = stristr(inptr, Key);
while (varptr)
{
// Move the remaining message up/down the buffer to make space for substitution
varlen = (int)strlen(Key);
vallen = (int)strlen(Values[i]);
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, Values[i], vallen);
inptr = endptr + 1;
varptr = stristr(inptr, Key);
}
i++;
}
}
// Build XML Attachment if Display Form is defined
if (WebMail->DisplayHTMLName)
BuildXMLAttachment(Session, Keys, Values, NumKeys);
// if Reply, attach original message to Body;
if (WebMail->isReply && WebMail->OrigBody)
{
char * NewBody = malloc(strlen(WebMail->Body) + strlen(WebMail->OrigBody) + 100);
sprintf(NewBody, "%s\r\n%s", WebMail->Body, WebMail->OrigBody);
free(WebMail->Body);
WebMail->Body = NewBody;
}
// Display Message for user to check and send
// fix any cr cr lf sequence
crcrptr = strstr(WebMail->Body, "\r\r");
while (crcrptr)
{
*crcrptr = ' ';
crcrptr = strstr(crcrptr, "\r\r");
}
if (WebMail->BID == NULL)
WebMail->BID = _strdup("");
*RLen = sprintf(Reply, CheckFormMsgPage, Session->Key, WebMail->To, WebMail->CC, WebMail->Subject, "Selected", "", "", WebMail->BID, WebMail->Body);
// Free the part strings
i = 0;
while (saveForfree[i])
free(saveForfree[i++]);
}
// XML Template Stuff
char XMLHeader [] =
"<?xml version=\"1.0\"?>\r\n"
"<RMS_Express_Form>\r\n"
" <form_parameters>\r\n"
" <xml_file_version>%s</xml_file_version>\r\n"
" <rms_express_version>%s</rms_express_version>\r\n"
" <submission_datetime>%s</submission_datetime>\r\n"
" <senders_callsign>%s</senders_callsign>\r\n"
" <grid_square>%s</grid_square>\r\n"
" <display_form>%s</display_form>\r\n"
" <reply_template>%s</reply_template>\r\n"
" </form_parameters>\r\n"
"<variables>\r\n"
" <msgto>%s</msgto>\r\n"
" <msgcc>%s</msgcc>\r\n"
" <msgsender>%s</msgsender>\r\n"
" <msgsubject>%s</msgsubject>\r\n"
" <msgbody>%s</msgbody>\r\n"
" <msgp2p>%s</msgp2p>\r\n"
" <msgisreply>%s</msgisreply>\r\n"
" <msgisforward>%s</msgisforward>\r\n"
" <msgisacknowledgement>%s</msgisacknowledgement>\r\n";
char XMLLine[] = " <%s>%s</%s>\r\n";
char XMLTrailer[] = "</variables>\r\n</RMS_Express_Form>\r\n";
char * doXMLTransparency(char * string)
{
// Make sure string doesn't contain forbidden XML chars (<>"'&)
char * newstring = malloc(5 * strlen(string) + 1); // If len is zero still need null terminator
char * in = string;
char * out = newstring;
char c;
c = *(in++);
while (c)
{
switch (c)
{
case '<':
strcpy(out, "&lt;");
out += 4;
break;
case '>':
strcpy(out, "&gt;");
out += 4;
break;
case '"':
strcpy(out, "&quot;");
out += 6;
break;
case '\'':
strcpy(out, "&apos;");
out += 6;
break;
case '&':
strcpy(out, "&amp;");
out += 5;
break;
default:
*(out++) = c;
}
c = *(in++);
}
*(out++) = 0;
return newstring;
}
VOID BuildXMLAttachment(struct HTTPConnectionInfo * Session, char * Keys[1000], char * Values[1000], int NumKeys)
{
// Create XML Attachment for form
WebMailInfo * WebMail = Session->WebMail;
char XMLName[MAX_PATH];
char * XMLPtr;
char DateString[80];
struct tm * tm;
time_t NOW = time(NULL);
int n;
int TotalFileSize = 0;
tm = gmtime(&NOW);
sprintf(DateString, "%04d%02d%02d%02d%02d%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
strcpy(XMLName, WebMail->DisplayHTMLName);
XMLName[strlen(XMLName) - 5] = 0; // remove .html
WebMail->XMLName = malloc(MAX_PATH);
WebMail->XML = XMLPtr = malloc(100000);
WebMail->XMLLen = 0;
sprintf(WebMail->XMLName, "RMS_Express_Form_%s.xml", XMLName);
XMLPtr += sprintf(XMLPtr, XMLHeader,
"1,0", VersionString,
DateString,
Session->User->Call,
"", //Grid
WebMail->DisplayHTMLName,
WebMail->ReplyHTMLName,
WebMail->To,
WebMail->CC,
Session->User->Call,
WebMail->OrigSubject,
"", // WebMail->OrigBody,
"False", // P2P
WebMail->isReply ? "True": "False",
"False", // Forward,
"False"); // Ack
// create XML lines for Key/Value Pairs
for (n = 0; n < NumKeys; n++)
{
if (Values[n] == NULL)
Values[n] = _strdup("");
XMLPtr += sprintf(XMLPtr, XMLLine, Keys[n], Values[n], Keys[n]);
}
if (WebMail->isReply)
{
if (WebMail->OrigBody)
{
char * goodXML = doXMLTransparency(WebMail->OrigBody);
XMLPtr += sprintf(XMLPtr, XMLLine, "MsgOriginalBody", goodXML, "MsgOriginalBody");
}
else
XMLPtr += sprintf(XMLPtr, XMLLine, "MsgOriginalBody", "", "MsgOriginalBody");
}
XMLPtr += sprintf(XMLPtr, "%s", XMLTrailer);
WebMail->XMLLen = (int)(XMLPtr - WebMail->XML);
}
char * BuildFormMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Keys[1000], char * Values[1000], int NumKeys)
{
// Create B2 message with template body and xml attachment
char * NewMsg = malloc(100000);
char * SaveMsg = NewMsg;
char * XMLPtr;
char DateString[80];
struct tm * tm;
char * FileName[100];
int FileLen[100];
char * FileBody[100];
int n, Files = 0;
int TotalFileSize = 0;
char Type[16] = "Private";
WebMailInfo * WebMail = Session->WebMail;
// Create a B2 Message
tm = gmtime((time_t *)&Msg->datecreated);
sprintf(DateString, "%04d%02d%02d%02d%02d%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
if (WebMail->DisplayHTMLName)
{
char XMLName[MAX_PATH];
strcpy(XMLName, WebMail->DisplayHTMLName);
XMLName[strlen(XMLName) - 5] = 0; // remove .html
FileName[0] = malloc(MAX_PATH);
FileBody[0] = malloc(100000);
Files = 1;
FileLen[0] = 0;
sprintf(FileName[0], "RMS_Express_Form_%s.xml", XMLName);
XMLPtr = FileBody[0];
XMLPtr += sprintf(XMLPtr, XMLHeader,
"1,0", VersionString,
DateString,
Session->User->Call,
"", //Grid
WebMail->DisplayHTMLName,
WebMail->ReplyHTMLName,
WebMail->OrigTo,
"", // CC
Session->User->Call,
WebMail->OrigSubject,
WebMail->OrigBody,
"false", // P2P,
"false", //Reply
"false", //Forward,
"false"); // Ack
// create XML lines for Key/Value Pairs
for (n = 0; n < NumKeys; n++)
{
if (Values[n] == NULL)
Values[n] = _strdup("");
XMLPtr += sprintf(XMLPtr, XMLLine, Keys[n], Values[n], Keys[n]);
}
XMLPtr += sprintf(XMLPtr, "%s", XMLTrailer);
FileLen[0] = (int)(XMLPtr - FileBody[0]);
}
sprintf(DateString, "%04d/%02d/%02d %02d:%02d",
tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min);
// Get Type
if (Msg->type == 'B')
strcpy(Type, "Bulletin");
else if (Msg->type == 'T')
strcpy(Type, "NTS");
// We put original To call in B2 Header
NewMsg += sprintf(NewMsg,
"MID: %s\r\nDate: %s\r\nType: %s\r\nFrom: %s\r\nTo: %s\r\nSubject: %s\r\nMbo: %s\r\n",
Msg->bid, DateString, Type, Msg->from, WebMail->To, Msg->title, BBSName);
NewMsg += sprintf(NewMsg, "Body: %d\r\n", (int)strlen(WebMail->Body));
for (n = 0; n < Files; n++)
{
char * p = FileName[n], * q;
// Remove any path
q = strchr(p, '\\');
while (q)
{
if (q)
*q++ = 0;
p = q;
q = strchr(p, '\\');
}
NewMsg += sprintf(NewMsg, "File: %d %s\r\n", FileLen[n], p);
}
NewMsg += sprintf(NewMsg, "\r\n");
strcpy(NewMsg, WebMail->Body);
NewMsg += strlen(WebMail->Body);
NewMsg += sprintf(NewMsg, "\r\n");
for (n = 0; n < Files; n++)
{
memcpy(NewMsg, FileBody[n], FileLen[n]);
NewMsg += FileLen[n];
free(FileName[n]);
free(FileBody[n]);
NewMsg += sprintf(NewMsg, "\r\n");
}
Msg->length = (int)strlen(SaveMsg);
Msg->B2Flags = B2Msg;
if (Files)
Msg->B2Flags |= Attachments;
if (WebMail->Body)
free(WebMail->Body);
WebMail->Body = SaveMsg;
return NULL;
}
VOID UpdateFormAction(char * Template, char * Key)
{
char * inptr, * saveptr;
char * varptr, * endptr;
size_t varlen, vallen;
char Submit[64];
sprintf(Submit, "/Webmail/Submit?%s", Key);
// First find the Form Action string and replace with our URL. It should have
// action="http://{FormServer}:{FormPort}" but some forms have localhost:8001 instead
// Also remove the OnSubmit if it contains the standard popup about having to close browser
inptr = Template;
saveptr = varptr = stristr(inptr, "<Form ");
if (varptr == NULL)
return;
varptr = stristr(inptr, " Action=");
if (varptr)
{
char delim = ' ';
varptr += 8; // to first char.
if (*varptr == '\"' || *varptr == '\'')
delim = *varptr++;
endptr = strchr(varptr, delim);
// Move the remaining message up/down the buffer to make space for substitution
varlen = endptr - varptr;
vallen = strlen(Submit);
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, Submit, vallen);
}
varptr = saveptr;
saveptr = varptr = stristr(inptr, " onsubmit=");
if (varptr)
{
char delim = ' ';
varptr += 10; // to first char.
if (*varptr == '\"' || *varptr == '\'')
delim = *varptr++;
endptr = strchr(varptr, delim);
// We want to remove onsubmit and delimiter
varptr = saveptr;
endptr++;
// Move the remaining message up/down the buffer to make space for substitution
varlen = endptr - varptr;
vallen = 0;
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, Submit, vallen);
}
// Some forms seem to have file://C:/RMS%20Express/Standard%20Templates/ instead of {FormFolder}
varptr = saveptr;
saveptr = varptr = stristr(inptr, "file://C:/RMS");
if (varptr)
{
// We need the last part of the name
char * start = varptr;
char * endptr = strchr(varptr, '"');
if (endptr)
*(endptr) = 0; // Null terminate for strlop
while (strchr(varptr, '/'))
varptr = strlop(varptr, '/');
*(endptr) = '"'; // Put Back
// We want to remove onsubmit and delimiter
varlen = varptr - saveptr;
endptr++;
// Move the remaining message up/down the buffer to make space for substitution
endptr = varptr + varlen;
memmove(saveptr + 12, varptr, strlen(varptr) + varlen); // copy null on end
memcpy(saveptr, "{FormFolder}", 12);
}
}
int ReplyToFormsMessage(struct HTTPConnectionInfo * Session, struct MsgInfo * Msg, char * Reply, BOOL Reenter)
{
WebMailInfo * WebMail = Session->WebMail;
KeyValues * txtKey = WebMail->XMLKeys;
int Len, i;
char * inptr, * ptr;
char * varptr, * endptr;
int varlen, vallen;
struct HtmlFormDir * Dir;
char * Template = FindXMLVariable(WebMail, "reply_template");
if (Template == NULL || Template[0] == 0)
return 0; // No Template
if (Reenter)
goto reEnter;
WebMail->isReply = TRUE;
if (WebMail->OrigBody)
free(WebMail->OrigBody);
WebMail->OrigBody = _strdup(WebMail->Body);
// Add "Re: " to Subject
ptr = WebMail->Subject;
WebMail->Subject = malloc(strlen(Msg->title) + 10);
sprintf(WebMail->Subject, "Re: %s", Msg->title);
// Set To: from From:
WebMail->To = malloc(80);
if (Msg->emailfrom[0])
sprintf(WebMail->To, "%s%s", Msg->from, Msg->emailfrom);
else
sprintf(WebMail->To, "%s", Msg->from);
if (ptr)
free(ptr);
WebMail->txtFileName = _strdup(Template);
// Read the .txt file
if (WebMail->txtFile)
free(WebMail->txtFile);
for (i = 0; i < FormDirCount; i++)
{
int n;
Dir = HtmlFormDirs[i];
WebMail->txtFile = CheckFile(Dir, WebMail->txtFileName);
if (WebMail->txtFile)
goto gotFile;
// Recurse any Subdirs
n = 0;
while (n < Dir->DirCount)
{
WebMail->txtFile = CheckFile(Dir->Dirs[n], WebMail->txtFileName);
if (WebMail->txtFile)
{
Dir = Dir->Dirs[n];
goto gotFile;
}
n++;
}
}
// Template Not Found
// Missing template
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Reply Template %s missing. Display as Text then Reply\");;window.history.back();</script></html>", WebMail->txtFileName);
return *WebMail->RLen;
gotFile:
WebMail->Dir = Dir;
reEnter:
if (ParsetxtTemplate(Session, WebMail->Dir, WebMail->txtFileName, TRUE) == FALSE)
return *WebMail->RLen; // processing <select> or <ask>
if (WebMail->InputHTMLName == NULL)
{
// This is a plain text template without HTML
/*
if (To == NULL)
To = "";
if (To[0] == 0 && WebMail->To && WebMail->To[0])
To = WebMail->To;
if (CC == NULL)
CC = "";
if (CC[0] == 0 && WebMail->CC && WebMail->CC[0])
CC = WebMail->CC;
if (Subject == NULL)
Subject = "";
if (Subject[0] == 0 && WebMail->Subject && WebMail->Subject[0])
Subject = WebMail->Subject;
if (MsgBody == NULL)
MsgBody = "";
if (MsgBody[0] == 0 && WebMail->Body && WebMail->Body[0])
MsgBody = WebMail->Body;
*WebMail->RLen = sprintf(WebMail->Reply, CheckFormMsgPage, Session->Key, To, CC, Subject, MsgBody);
*/
return *WebMail->RLen;
}
Template = CheckFile(WebMail->Dir, WebMail->InputHTMLName);
if (Template == NULL)
{
// Missing HTML
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Reply HTML %s missing. Display as Text then Reply\");;window.history.back();</script></html>", WebMail->InputHTMLName);
return *WebMail->RLen;
}
// I've going to update the template in situ, as I can't see a better way
// of making sure all occurances of variables in any order are substituted.
// The space allocated to Template is twice the size of the file
// to allow for insertions
UpdateFormAction(Template, Session->Key); // Update "Submit" Action
// Search for "{var }" strings in form and replace with
// corresponding variable from XML
while (txtKey->Key)
{
char Key[256] = "{var ";
strcpy(&Key[5], txtKey->Key);
strcat(Key, "}");
inptr = Template;
varptr = stristr(inptr, Key);
while (varptr)
{
// Move the remaining message up/down the buffer to make space for substitution
varlen = (int)strlen(Key);
if (txtKey->Value)
vallen = (int)strlen(txtKey->Value);
else vallen = 0;
endptr = varptr + varlen;
memmove(varptr + vallen, endptr, strlen(endptr) + 1); // copy null on end
memcpy(varptr, txtKey->Value, vallen);
inptr = endptr + 1;
varptr = stristr(inptr, Key);
}
txtKey++;
}
// Remove </body></html> from end as we add it on later
ptr = stristr(Template, "</body></html>");
if (ptr)
*ptr = 0;
Len = sprintf(Reply, "%s", Template);
free(Template);
return Len;
}
char * CheckFile(struct HtmlFormDir * Dir, char * FN)
{
struct stat STAT;
FILE * hFile;
char MsgFile[MAX_PATH];
char * MsgBytes;
int ReadLen;
int FileSize;
#ifndef WIN32
// Need to do case insensitive file search
DIR *dir;
struct dirent *entry;
char name[256];
sprintf(name, "%s/%s/%s", BPQDirectory, Dir->FormSet, Dir->DirName);
if (!(dir = opendir(name)))
{
Debugprintf("cant open forms dir %s %s %d", Dir->DirName, name, errno);
return 0;
}
while ((entry = readdir(dir)) != NULL)
{
if (entry->d_type == DT_DIR)
continue;
if (stricmp(entry->d_name, FN) == 0)
{
sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), Dir->FormSet, Dir->DirName, entry->d_name);
break;
}
}
closedir(dir);
#else
sprintf(MsgFile, "%s/%s/%s/%s", GetBPQDirectory(), Dir->FormSet, Dir->DirName, FN);
#endif
printf("%s\n", MsgFile);
if (stat(MsgFile, &STAT) != -1)
{
hFile = fopen(MsgFile, "rb");
if (hFile == 0)
{
MsgBytes = _strdup("File is missing");
return MsgBytes;
}
FileSize = STAT.st_size;
MsgBytes = malloc(FileSize * 10); // Allow plenty of room for template substitution
ReadLen = (int)fread(MsgBytes, 1, FileSize, hFile);
MsgBytes[FileSize] = 0;
fclose(hFile);
printf("%d %s\n", strlen(MsgBytes), MsgBytes);
return MsgBytes;
}
return NULL;
}
BOOL DoSelectPrompt(struct HTTPConnectionInfo * Session, char * Select)
{
// Send a Popup window to select value. Reply handling code will update template then reenter ParsetxtTemplate
char popuphddr[] =
"<html><body align=center background='/background.jpg'>"
"<script>"
"function myFunction() {var x = document.getElementById('Sel').value;"
"var Key = \"%s\";"
"var param = \"toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=no,resizable=no,titlebar=no,toobar=no\";"
"window.open(\"/WebMail/DoSelect\" + '?' + Key + '&' + x,'_self');"
"}"
"</script>"
"<div align=center>%s<br><br>"
"<table border=1 cellpadding=2 bgcolor=white>"
"<tr><td><select size=%d id='Sel' size=10 onclick=myFunction()>";
char popup[10000];
int i, vars = 0;
char * ptr, * ptr1;
char * prompt;
char * var[100];
WebMailInfo * WebMail = Session->WebMail;
char * SelCopy = _strdup(Select + 8); // Skip "<select "
ptr = strchr(SelCopy, '>');
if (ptr)
*ptr = 0;
ptr = SelCopy;
if (*ptr == '"')
{
// String has " " round it
ptr++;
ptr1 = strchr(ptr, '"');
if (ptr1 == NULL)
goto returnDuff;
*(ptr1++) = 0;
prompt = ptr;
}
else
{
// Normal comma terminated
ptr1 = strchr(ptr, ',');
if (ptr1 == NULL)
goto returnDuff;
*(ptr1++) = 0;
prompt = ptr;
}
ptr = ptr1;
while (ptr && ptr[0])
{
if (*ptr == '"')
{
// String has " " round it
ptr++;
ptr1 = strchr(ptr, '"');
if (ptr1 == NULL)
goto returnDuff;
*(ptr1++) = 0;
while(ptr1 && *ptr1 == ',')
ptr1++;
}
else
{
// Normal comma terminated
ptr1 = strchr(ptr, ',');
if (ptr1)
*(ptr1++) = 0;
}
var[vars++] = ptr;
ptr = ptr1;
}
sprintf(popup, popuphddr, Session->Key, prompt, vars + 1);
for (i = 0; i < vars; i++)
{
char * key = strlop(var[i], '=');
if (key == NULL)
key = var[i];
sprintf(popup, "%s <option value='%s'>%s", popup, key, var[i]);
}
sprintf(popup, "%s</select></td></tr></table><br><input onclick=window.history.back() value=Back type=button class='btn'></div>", popup);
*WebMail->RLen = sprintf(WebMail->Reply, "%s", popup);
free(SelCopy);
return TRUE;
returnDuff:
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Template <select> Corrupt.\");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
free(SelCopy);
return TRUE;
}
BOOL DoAskPrompt(struct HTTPConnectionInfo * Session, char * Select)
{
return TRUE;
}
VOID ProcessSelectResponse(struct HTTPConnectionInfo * Session, char * URLParams)
{
// User has entered a response for a Template <Select>. Update Template and re-renter ParsetxtTemplate
WebMailInfo * WebMail = Session->WebMail;
char * valptr, * varptr, * endptr;
size_t varlen, vallen;
char * Select = WebMail->txtFile;
if (Select == 0)
{
// Missing template
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Template missing. Was back Button used? \");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
return;
}
Select = stristr(Select, "<Select ");
if (Select == 0)
{
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Template Corrupt.\");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
return;
}
varptr = Select;
endptr = strchr(Select, '>');
if (endptr == NULL)
{
*WebMail->RLen = sprintf(WebMail->Reply, "<html><script>alert(\"Template Corrupt.\");window.location.href = '/Webmail/WebMail?%s';</script></html>", Session->Key);
return;
}
*endptr = 0;
varlen = endptr - varptr;
valptr = URLParams;
// Move the remaining message up/down the buffer to make space for substitution
vallen = strlen(valptr);
endptr = varptr + varlen;
memcpy(varptr, valptr, vallen);
memmove(varptr + vallen, endptr + 1, strlen(endptr + 1) + 1); // copy null on end
if (WebMail->isReply)
*WebMail->RLen = ReplyToFormsMessage(Session, Session->Msg, WebMail->Reply, TRUE);
else
GetPage(Session, NULL);
return ;
}
BOOL ParsetxtTemplate(struct HTTPConnectionInfo * Session, struct HtmlFormDir * Dir, char * FN, BOOL isReply)
{
WebMailInfo * WebMail = Session->WebMail;
KeyValues * txtKey = WebMail->txtKeys;
char * MsgBytes;
char * txtFile;
char * ptr, *ptr1;
char * InputName = NULL; // HTML to input message
char * ReplyName = NULL;
char * To = NULL;
char * Subject = NULL;
char * MsgBody = NULL;
char * Select = NULL;
char * Ask = NULL;
char Date[16];
char UDate[16];
char DateTime[32];
char UDateTime[32];
char Day[16];
char UDay[16];
char UDTG[32];
char Seq[16];
char FormDir[MAX_PATH];
double Lat;
double Lon;
char LatString[32], LonString[32], GPSString[32];
BOOL GPSOK;
struct tm * tm;
time_t NOW;
// Template is now read before entering here
MsgBytes = WebMail->txtFile;
// if Template uses <Select> or <Ask> get the values
Select = stristr(MsgBytes, "<Select ");
Ask = stristr(MsgBytes, "<Ask ");
if (Select && Ask)
{
// use whichever came first
if (Select < Ask)
{
DoSelectPrompt(Session, Select);
return FALSE;
}
else
{
DoAskPrompt(Session, Ask);
return FALSE;
}
}
if (Select)
{
DoSelectPrompt(Session, Select);
return FALSE;
}
if (Ask)
{
DoAskPrompt(Session, Ask);
return FALSE;
}
NOW = time(NULL);
tm = localtime(&NOW);
sprintf(Date, "%04d-%02d-%02d",
tm->tm_year + 1900,tm->tm_mon + 1, tm->tm_mday);
sprintf(DateTime, "%04d-%02d-%02d %02d:%02d:%02d",
tm->tm_year + 1900,tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
strcpy(Day, longday[tm->tm_wday]);
tm = gmtime(&NOW);
sprintf(UDate, "%04d-%02d-%02dZ",
tm->tm_year + 1900,tm->tm_mon + 1, tm->tm_mday);
sprintf(UDateTime, "%04d-%02d-%02d %02d:%02d:%02dZ",
tm->tm_year + 100,tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
sprintf(UDTG, "%02d%02d%02dZ %s %04d",
tm->tm_mday, tm->tm_hour, tm->tm_min, month[tm->tm_mon], tm->tm_year + 1900);
strcpy(UDay, longday[tm->tm_wday]);
sprintf(Seq, "%d", Session->User->WebSeqNo);
sprintf(FormDir, "/WebMail/WMFile/%s/%s/", WebMail->Dir->FormSet, WebMail->Dir->DirName);
// Keep SeqNo at front
txtKey->Key = _strdup("<SeqNum>");
txtKey++->Value = _strdup(Seq);
txtKey->Key = _strdup("<DateTime>");
txtKey++->Value = _strdup(DateTime);
txtKey->Key = _strdup("<UDateTime>");
txtKey++->Value = _strdup(UDateTime);
txtKey->Key = _strdup("<Date>");
txtKey++->Value = _strdup(Date);
txtKey->Key = _strdup("<UDate>");
txtKey++->Value = _strdup(UDate);
txtKey->Key = _strdup("<Time>");
txtKey++->Value = _strdup(&DateTime[11]);
txtKey->Key = _strdup("<UTime>");
txtKey++->Value = _strdup(&UDateTime[11]);
txtKey->Key = _strdup("<Day>");
txtKey++->Value = _strdup(Day);
txtKey->Key = _strdup("<UDay>");
txtKey++->Value = _strdup(UDay);
txtKey->Key = _strdup("<UDTG>");
txtKey++->Value = _strdup(UDTG);
// Try to get position from APRS
GPSOK = GetAPRSLatLon(&Lat, &Lon);
GPSOK = GetAPRSLatLonString(&LatString[1], &LonString[1]);
memmove(LatString, &LatString[1], 2);
memmove(LonString, &LonString[1], 3);
LatString[2] = '-';
LonString[3] = '-';
sprintf(GPSString,"%s %s", LatString, LonString);
txtKey->Key = _strdup("<GPS>");
if (GPSOK)
txtKey++->Value = _strdup(GPSString);
else
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<Position>");
txtKey++->Value = _strdup(GPSString);
txtKey->Key = _strdup("<ProgramVersion>");
txtKey++->Value = _strdup(VersionString);
txtKey->Key = _strdup("<Callsign>");
txtKey++->Value = _strdup(Session->User->Call);
txtKey->Key = _strdup("<MsgTo>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgCc>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgSender>");
txtKey++->Value = _strdup(Session->User->Call);
txtKey->Key = _strdup("<MsgSubject>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgBody>");
// if (WebMail->OrigBody)
// txtKey++->Value = _strdup(WebMail->OrigBody);
// else
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgP2P>");
txtKey++->Value = _strdup("");
if (isReply)
{
txtKey->Key = _strdup("<MsgIsReply>");
txtKey++->Value = _strdup("True");
txtKey->Key = _strdup("<MsgIsForward>");
txtKey++->Value = _strdup("False");
txtKey->Key = _strdup("<MsgIsAcknowledgement>");
txtKey++->Value = _strdup("False");
txtKey->Key = _strdup("<MsgOriginalSubject>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalSender>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalBody>");
txtKey++->Value = _strdup(WebMail->Body);
txtKey->Key = _strdup("<MsgOriginalID>");
txtKey++->Value = _strdup(WebMail->Msg->bid);
// Get Timestamp from Message
tm = gmtime((time_t *)&WebMail->Msg->datecreated);
sprintf(Date, "%02d-%02d-%02d",
tm->tm_year - 100,tm->tm_mon + 1, tm->tm_mday);
sprintf(DateTime, "%02d-%02d-%02d %02d:%02d",
tm->tm_year - 100,tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
strcpy(Day, longday[tm->tm_wday]);
tm = gmtime((time_t *)&WebMail->Msg->datecreated);
sprintf(UDate, "%02d-%02d-%02dZ",
tm->tm_year - 100,tm->tm_mon + 1, tm->tm_mday);
sprintf(UDateTime, "%02d-%02d-%02d %02d:%02dZ",
tm->tm_year - 100,tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
sprintf(UDTG, "%02d%02d%02dZ %s %04d",
tm->tm_mday, tm->tm_hour, tm->tm_min, month[tm->tm_mon], tm->tm_year + 1900);
txtKey->Key = _strdup("<MsgOriginalDate>");
txtKey++->Value = _strdup(UDate);
txtKey->Key = _strdup("<MsgOriginalUtcDate>");
txtKey++->Value = _strdup(UDate);
txtKey->Key = _strdup("<MsgOriginalUtcTime>");
txtKey++->Value = _strdup(&UDateTime[9]);
txtKey->Key = _strdup("<MsgOriginalLocalDate>");
txtKey++->Value = _strdup(Date);
txtKey->Key = _strdup("<MsgOriginalLocalTime>");
txtKey++->Value = _strdup(&UDateTime[9]);
txtKey->Key = _strdup("<MsgOriginalDTG>");
txtKey++->Value = _strdup(UDTG);
txtKey->Key = _strdup("<MsgOriginalSize>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalAttachmentCount>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalXML>");
txtKey++->Value = _strdup("");
}
else
{
txtKey->Key = _strdup("<MsgIsReply>");
txtKey++->Value = _strdup("False");
txtKey->Key = _strdup("<MsgIsForward>");
txtKey++->Value = _strdup("False");
txtKey->Key = _strdup("<MsgIsAcknowledgement>");
txtKey++->Value = _strdup("False");
txtKey->Key = _strdup("<MsgOriginalSubject>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalSender>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalBody>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalID>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalDate>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalUtcDate>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalUtcTime>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalLocalDate>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalLocalTime>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalDTG>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalSize>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalAttachmentCount>");
txtKey++->Value = _strdup("");
txtKey->Key = _strdup("<MsgOriginalXML>");
txtKey++->Value = _strdup("");
}
txtKey->Key = _strdup("<FormFolder>");
txtKey++->Value = _strdup(FormDir); //Form Folder
// Do standard Variable substitution on file
DoStandardTemplateSubsitutions(Session, WebMail->txtFile);
txtFile = _strdup(WebMail->txtFile); // We chop up and modify bits of txtFile, so need copy
// Scan template line by line extracting useful information
ptr = txtFile;
ptr1 = strchr(ptr, '\r');
while (ptr1)
{
if (_memicmp(ptr, "Msg:", 4) == 0)
{
// Rest is message body. May need <var> substitutions
if (WebMail->Body)
free(WebMail->Body);
WebMail->Body = _strdup(ptr + 4);
break;
}
// Can now terminate lines
*ptr1++ = 0;
while (*ptr1 == '\r' || *ptr1 == '\n')
*ptr1++ = 0;
if (_memicmp(ptr, "Form:", 5) == 0)
{
InputName = &ptr[5];
while (*InputName == ' ') // Remove leading spaces
InputName++;
WebMail->InputHTMLName = _strdup(InputName);
WebMail->DisplayHTMLName = strlop(WebMail->InputHTMLName, ',');
if (WebMail->DisplayHTMLName)
{
while (*WebMail->DisplayHTMLName == ' ') // Remove leading spaces
WebMail->DisplayHTMLName++;
WebMail->DisplayHTMLName = _strdup(WebMail->DisplayHTMLName);
}
}
else if (_memicmp(ptr, "ReplyTemplate:",14) == 0)
{
char * end;
ReplyName = &ptr[14];
while (*ReplyName == ' ')
ReplyName++;
strlop(ReplyName, '\r'); // Terminate
// Filename may have embedded spaces, so have to scan from end, not use strlop
end = ReplyName + strlen(ReplyName) - 1;
while (*end == ' ')
*end-- = 0;
WebMail->ReplyHTMLName = _strdup(ReplyName);
}
else if (_memicmp(ptr, "To:", 3) == 0)
{
if (strlen(ptr) > 5)
WebMail->To = _strdup(&ptr[3]);
}
else if (_memicmp(ptr, "Subj:", 5) == 0)
{
if (ptr[5] == ' ') // May have space after :
ptr++;
if (strlen(ptr) > 6)
WebMail->Subject = _strdup(&ptr[5]);
}
else if (_memicmp(ptr, "Subject:", 8) == 0)
{
if (ptr[8] == ' ')
ptr++;
if (strlen(ptr) > 9)
WebMail->Subject = _strdup(&ptr[8]);
}
else if (_memicmp(ptr, "Def:", 4) == 0)
{
// Def: MsgOriginalBody=<var MsgOriginalBody>
char * val = strlop(ptr, '=');
if (val)
{
// Make Room for {} delimiters
memmove(ptr, ptr + 1, strlen(ptr));
ptr[3] = '<';
ptr[strlen(ptr)] = '>';
while (val[strlen(val) - 1] == ' ')
val[strlen(val) - 1] = 0;
txtKey->Key = _strdup(&ptr[3]);
txtKey++->Value = _strdup(val); //Form Folder
}
}
else if (_memicmp(ptr, "Type:", 5) == 0)
{
if (stristr(ptr, "Winlink"))
WebMail->Winlink = TRUE;
else if (stristr(ptr, "P2P"))
WebMail->P2P = TRUE;
else if (stristr(ptr, "Packet"))
WebMail->Packet = TRUE;
}
else if (_memicmp(ptr, "SeqInc:", 7) == 0)
{
int SeqInc = 1;
while (ptr[7] == ' ')
ptr++;
if (strlen(&ptr[7]))
SeqInc = atoi(&ptr[7]);
Session->User->WebSeqNo += SeqInc;
sprintf(WebMail->txtKeys[0].Value, "%d", Session->User->WebSeqNo);
}
else if (_memicmp(ptr, "SeqSet:", 7) == 0)
{
int SeqSet = 0;
while (ptr[7] == ' ')
ptr++;
if (strlen(&ptr[7]))
SeqSet = atoi(&ptr[7]);
Session->User->WebSeqNo = SeqSet;
sprintf(WebMail->txtKeys[0].Value, "%d", Session->User->WebSeqNo);
}
// Attach:file1, file2, ... - If present, specifies one or more files to attach to the message.
//Readonly: Yes | No - If Readonly is set to Yes, then the message is created by the form and it cannot be edited by the user.
ptr = ptr1;
ptr1 = strchr(ptr, '\r');
}
if (WebMail->ReplyHTMLName == NULL)
WebMail->ReplyHTMLName = _strdup("");
free(txtFile);
return TRUE;
}
VOID FormatTime2(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);
}
VOID DownloadAttachments(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Param)
{
WebMailInfo * WebMail = Session->WebMail;
char TimeString[64];
char FileTimeString[64];
int file = atoi(Param);
file--; // Sent at +1 in case no downloadable attachments
if (file == -1)
{
// User has gone back, then selected "No file Selected"
// Or no files
*RLen = sprintf(Reply, "<html><script>window.history.back();</script></html>");
return;
}
FormatTime2(FileTimeString, time(NULL));
FormatTime2(TimeString, time(NULL));
*RLen = sprintf(Reply, "HTTP/1.1 200 OK\r\nContent-Length: %d\r\n"
"Content-Type: application/octet-stream\r\n"
"Content-Disposition: attachment; filename=\"%s\"\r\n"
"Date: %s\r\n"
"Last-Modified: %s\r\n"
"\r\n", WebMail->FileLen[file], WebMail->FileName[file], TimeString, FileTimeString);
memcpy(&Reply[*RLen], WebMail->FileBody[file], WebMail->FileLen[file]);
*RLen += WebMail->FileLen[file];
return;
}
VOID getAttachmentList(struct HTTPConnectionInfo * Session, char * Reply, int * RLen, char * Rest)
{
char popuphddr[] =
"<html><body align=center background='/background.jpg'>"
"<script>"
"function myFunction() {var x = document.getElementById('Sel').value;"
"var Key = \"%s\";"
"var param = \"toolbar=yes,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,titlebar=yes,toobar=yes\";"
"window.open(\"/WebMail/GetDownLoad\" + '?' + Key + '&' + x,'_self', param);"
"}"
"</script>"
"<div align=center>Note files over 100K long can't be downloaded<br><br>"
"<table border=1 cellpadding=2 bgcolor=white>"
"<tr><td><select size=%d id='Sel' size=10 onclick=myFunction()>";
char popup[10000];
int i;
WebMailInfo * WebMail = Session->WebMail;
sprintf(popup, popuphddr, Session->Key, WebMail->Files);
for (i = 0; i < WebMail->Files; i++)
{
if(WebMail->FileLen[i] < 100000)
sprintf(popup, "%s <option value=%d>%s (Len %d)", popup, i + 1, WebMail->FileName[i], WebMail->FileLen[i]);
}
sprintf(popup, "%s</select></td></tr></table><br><input onclick=window.history.back() value=Back type=button class='btn'></div>", popup);
*RLen = sprintf(Reply, "%s", popup);
return;
}
char * WebFindPart(char ** Msg, char * Boundary, int * PartLen, char * End)
{
char * ptr = *Msg;
char * Msgptr = *Msg;
size_t BLen = strlen(Boundary);
char * Part;
while(ptr < End) // Just in case we run off end
{
if (*ptr == '-' && *(ptr+1) == '-')
{
if (memcmp(&ptr[2], Boundary, BLen) == 0)
{
// Found Boundary
size_t Partlen = ptr - Msgptr;
Part = malloc(Partlen + 1);
memcpy(Part, Msgptr, Partlen);
Part[Partlen] = 0;
*Msg = ptr + BLen + 4;
*PartLen = (int)Partlen;
return Part;
}
}
ptr ++;
}
return NULL;
}
int ProcessWebmailWebSock(char * MsgPtr, char * OutBuffer)
{
int Len = 129;
char * Key = strlop(MsgPtr, '&');
struct HTTPConnectionInfo * Session;
struct UserInfo * User;
int m;
struct MsgInfo * Msg;
char * ptr = &OutBuffer[10]; // allow room for full payload length (64 bit)
int n = NumberofMessages;
char Via[64];
int Count = 0;
if (Key == 0)
return 0;
Session = FindWMSession(Key);
if (Session == NULL)
return 0;
User = Session->User;
// Outbuffer is 250000
// ptr += sprintf(ptr, "<div align=left id=\"main\" style=\"overflow:scroll;\">\r\n"
ptr += sprintf(ptr, "<pre align=left>");
ptr += sprintf(ptr, "%s", " # Date XX Len To @ From Subject\r\n\r\n");
for (m = LatestMsg; m >= 1; m--)
{
if (ptr > &OutBuffer[244000])
break; // protect buffer
Msg = GetMsgFromNumber(m);
if (Msg == 0 || Msg->type == 0 || Msg->status == 0)
continue; // Protect against corrupt messages
if (Msg && CheckUserMsg(Msg, User->Call, User->flags & F_SYSOP))
{
char UTF8Title[4096];
char * EncodedTitle;
// List if it is the right type and in the page range we want
if (Session->WebMailTypes[0] && strchr(Session->WebMailTypes, Msg->type) == 0)
continue;
// All Types or right Type. Check Mine Flag
if (Session->WebMailMine)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0 && strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyTX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->from) != 0)
continue;
}
if (Session->WebMailMyRX)
{
// Only list if to or from me
if (strcmp(User->Call, Msg->to) != 0)
continue;
}
if (Count++ < Session->WebMailSkip)
continue;
strcpy(Via, Msg->via);
strlop(Via, '.');
// make sure title is HTML safe (no < > etc) and UTF 8 encoded
EncodedTitle = doXMLTransparency(Msg->title);
memset(UTF8Title, 0, 4096); // In case convert fails part way through
ConvertTitletoUTF8(Session->WebMail, EncodedTitle, UTF8Title, 4095);
free(EncodedTitle);
ptr += sprintf(ptr, "<a href=/WebMail/WM?%s&%d>%6d</a> %s %c%c %5d %-8s%-8s%-8s%s\r\n",
Key, Msg->number, Msg->number,
FormatDateAndTime((time_t)Msg->datecreated, TRUE), Msg->type,
Msg->status, Msg->length, Msg->to, Via,
Msg->from, UTF8Title);
n--;
if (n == 0)
break;
}
}
ptr += sprintf(ptr, "%s</pre> \r\n", ptr);
Len = ptr - &OutBuffer[10];
OutBuffer[0] = 0x81; // Fin, Data
if (Len < 126)
{
OutBuffer[1] = Len;
memmove(&OutBuffer[2], &OutBuffer[10], Len);
return Len + 2;
}
else if (Len < 65536)
{
OutBuffer[1] = 126; // Unmasked, Extended Len 16
OutBuffer[2] = Len >> 8;
OutBuffer[3] = Len & 0xff;
memmove(&OutBuffer[4], &OutBuffer[10], Len);
return Len + 4;
}
else
{
OutBuffer[1] = 127; // Unmasked, Extended Len 64 bits
// Len is 32 bits, so pad with zeros
OutBuffer[2] = 0;
OutBuffer[3] = 0;
OutBuffer[4] = 0;
OutBuffer[5] = 0;
OutBuffer[6] = (Len >> 24) & 0xff;
OutBuffer[7] = (Len >> 16) & 0xff;
OutBuffer[8] = (Len >> 8) & 0xff;
OutBuffer[9] = Len & 0xff;
return Len + 10;
}
}