6332 lines
151 KiB
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 <input size=60 id='To' name='To' value='%s'>%s<br>"
|
|
"Subject <input size=60 id='Subj' name='Subj' value=\"%s\"> "
|
|
// "<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 "
|
|
"<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 </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 <input size=60 id='To' name='To' value='%s'><br>"
|
|
"CC <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 "
|
|
"<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[] =
|
|
" <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[] =
|
|
" <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, "<");
|
|
out += 4;
|
|
break;
|
|
|
|
case '>':
|
|
|
|
strcpy(out, ">");
|
|
out += 4;
|
|
break;
|
|
|
|
case '"':
|
|
|
|
strcpy(out, """);
|
|
out += 6;
|
|
break;
|
|
|
|
case '\'':
|
|
|
|
strcpy(out, "'");
|
|
out += 6;
|
|
break;
|
|
|
|
case '&':
|
|
|
|
strcpy(out, "&");
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|