|
|
@@ -274,6 +274,60 @@ |
|
|
return root + "\\" + folder + "\\WindowsPowerShell\\v1.0\\powershell.exe"; |
|
|
return root + "\\" + folder + "\\WindowsPowerShell\\v1.0\\powershell.exe"; |
|
|
} |
|
|
} |
|
|
function quoted(value) { return '"' + value + '"'; } |
|
|
function quoted(value) { return '"' + value + '"'; } |
|
|
|
|
|
function writeJsonFile(path, value) { |
|
|
|
|
|
var stream = new ActiveXObject("ADODB.Stream"); |
|
|
|
|
|
try { |
|
|
|
|
|
stream.Type = 2; |
|
|
|
|
|
stream.Charset = "utf-8"; |
|
|
|
|
|
stream.Open(); |
|
|
|
|
|
stream.WriteText(JSON.stringify(value)); |
|
|
|
|
|
stream.SaveToFile(path, 2); |
|
|
|
|
|
} finally { if (stream.State === 1) stream.Close(); } |
|
|
|
|
|
} |
|
|
|
|
|
function readJsonFile(path) { |
|
|
|
|
|
var stream = new ActiveXObject("ADODB.Stream"); |
|
|
|
|
|
try { |
|
|
|
|
|
stream.Type = 2; |
|
|
|
|
|
stream.Charset = "utf-8"; |
|
|
|
|
|
stream.Open(); |
|
|
|
|
|
stream.LoadFromFile(path); |
|
|
|
|
|
return JSON.parse(stream.ReadText().replace(/^\uFEFF/, "")); |
|
|
|
|
|
} finally { if (stream.State === 1) stream.Close(); } |
|
|
|
|
|
} |
|
|
|
|
|
function finishHiddenTool(job) { |
|
|
|
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
|
|
|
var result; |
|
|
|
|
|
try { |
|
|
|
|
|
if (!fs.FileExists(job.resultPath)) throw new Error("Helper exited without a result"); |
|
|
|
|
|
result = readJsonFile(job.resultPath); |
|
|
|
|
|
} finally { |
|
|
|
|
|
if (fs.FileExists(job.requestPath)) fs.DeleteFile(job.requestPath); |
|
|
|
|
|
if (fs.FileExists(job.resultPath)) fs.DeleteFile(job.resultPath); |
|
|
|
|
|
} |
|
|
|
|
|
if (!result.Success) throw new Error(result.Error || "Helper failed"); |
|
|
|
|
|
return result.Output || ""; |
|
|
|
|
|
} |
|
|
|
|
|
function startHiddenTool(scriptName, parameters, wait) { |
|
|
|
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
|
|
|
var folder = fs.BuildPath(projectRoot(), "temp"); |
|
|
|
|
|
if (!fs.FolderExists(folder)) fs.CreateFolder(folder); |
|
|
|
|
|
var requestPath = fs.BuildPath(folder, fs.GetTempName() + ".request.json"); |
|
|
|
|
|
var job = { requestPath: requestPath, resultPath: requestPath + ".result.json", |
|
|
|
|
|
startedAt: new Date().getTime(), warned: false }; |
|
|
|
|
|
var bridge = fs.BuildPath(projectRoot(), "tools\\run-hidden-tool.ps1"); |
|
|
|
|
|
var command = quoted(powerShellHost()) + " -NoProfile -ExecutionPolicy Bypass -File " + |
|
|
|
|
|
quoted(bridge) + " -RequestPath " + quoted(job.requestPath) + |
|
|
|
|
|
" -ResultPath " + quoted(job.resultPath); |
|
|
|
|
|
writeJsonFile(job.requestPath, { ScriptName: scriptName, |
|
|
|
|
|
ConfigPath: fs.BuildPath(projectRoot(), "config.ini"), Parameters: parameters || {} }); |
|
|
|
|
|
try { |
|
|
|
|
|
new ActiveXObject("WScript.Shell").Run(command, 0, wait); |
|
|
|
|
|
return wait ? finishHiddenTool(job) : job; |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
if (fs.FileExists(job.requestPath)) fs.DeleteFile(job.requestPath); |
|
|
|
|
|
throw error; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
function configurePassword() { |
|
|
function configurePassword() { |
|
|
try { |
|
|
try { |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
@@ -289,18 +343,11 @@ |
|
|
function sendInternalTest() { |
|
|
function sendInternalTest() { |
|
|
try { |
|
|
try { |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var root = projectRoot(); |
|
|
|
|
|
var settings = readSettings(fs.BuildPath(root, "config.ini")); |
|
|
|
|
|
|
|
|
var settings = readSettings(fs.BuildPath(projectRoot(), "config.ini")); |
|
|
if (!settings.SMTP_TEST_TO) throw new Error("Set SMTP_TEST_TO in config.ini first"); |
|
|
if (!settings.SMTP_TEST_TO) throw new Error("Set SMTP_TEST_TO in config.ini first"); |
|
|
if (!window.confirm("Send one internal SMTP test to " + settings.SMTP_TEST_TO + "?")) return; |
|
|
if (!window.confirm("Send one internal SMTP test to " + settings.SMTP_TEST_TO + "?")) return; |
|
|
var script = fs.BuildPath(root, "tools\\test-smtp-message.ps1"); |
|
|
|
|
|
var command = quoted(powerShellHost()) + " -NoProfile -ExecutionPolicy Bypass -File " + |
|
|
|
|
|
quoted(script) + " -Send"; |
|
|
|
|
|
var process = new ActiveXObject("WScript.Shell").Exec(command); |
|
|
|
|
|
var output = process.StdOut.ReadAll(); |
|
|
|
|
|
var errors = process.StdErr.ReadAll(); |
|
|
|
|
|
document.getElementById("transportMessage").innerText = |
|
|
document.getElementById("transportMessage").innerText = |
|
|
(process.ExitCode === 0 ? "" : "Test failed. ") + output + errors; |
|
|
|
|
|
|
|
|
runTemplateTool("test-smtp-message.ps1", { Send: true }); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
document.getElementById("transportMessage").innerText = "Test failed: " + error.message; |
|
|
document.getElementById("transportMessage").innerText = "Test failed: " + error.message; |
|
|
} |
|
|
} |
|
|
@@ -336,23 +383,14 @@ |
|
|
if (db !== null && db.State === 1) db.Close(); |
|
|
if (db !== null && db.State === 1) db.Close(); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
function runTemplateTool(scriptName, args) { |
|
|
|
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
|
|
|
var script = fs.BuildPath(projectRoot(), "tools\\" + scriptName); |
|
|
|
|
|
var configPath = fs.BuildPath(projectRoot(), "config.ini"); |
|
|
|
|
|
var command = quoted(powerShellHost()) + " -NoProfile -ExecutionPolicy Bypass -File " + |
|
|
|
|
|
quoted(script) + " -ConfigPath " + quoted(configPath) + " " + args; |
|
|
|
|
|
var process = new ActiveXObject("WScript.Shell").Exec(command); |
|
|
|
|
|
var output = process.StdOut.ReadAll(); |
|
|
|
|
|
var errors = process.StdErr.ReadAll(); |
|
|
|
|
|
if (process.ExitCode !== 0) throw new Error((output + errors).replace(/^\s+|\s+$/g, "")); |
|
|
|
|
|
return output.replace(/^\s+|\s+$/g, ""); |
|
|
|
|
|
|
|
|
function runTemplateTool(scriptName, parameters) { |
|
|
|
|
|
return startHiddenTool(scriptName, parameters, true); |
|
|
} |
|
|
} |
|
|
function importTemplate() { |
|
|
function importTemplate() { |
|
|
try { |
|
|
try { |
|
|
var path = document.getElementById("templatePath").value; |
|
|
var path = document.getElementById("templatePath").value; |
|
|
if (!path || path.indexOf('"') !== -1) throw new Error("Select a template file"); |
|
|
if (!path || path.indexOf('"') !== -1) throw new Error("Select a template file"); |
|
|
var result = runTemplateTool("import-template.ps1", "-Path " + quoted(path)); |
|
|
|
|
|
|
|
|
var result = runTemplateTool("import-template.ps1", { Path: path }); |
|
|
document.getElementById("templateMessage").innerText = result; |
|
|
document.getElementById("templateMessage").innerText = result; |
|
|
refreshTemplates(); |
|
|
refreshTemplates(); |
|
|
refreshStatus(); |
|
|
refreshStatus(); |
|
|
@@ -364,7 +402,7 @@ |
|
|
try { |
|
|
try { |
|
|
var id = document.getElementById("templateVersion").value; |
|
|
var id = document.getElementById("templateVersion").value; |
|
|
if (!/^[1-9][0-9]*$/.test(id)) throw new Error("Select an imported template"); |
|
|
if (!/^[1-9][0-9]*$/.test(id)) throw new Error("Select an imported template"); |
|
|
var file = runTemplateTool("preview-template.ps1", "-TemplateId " + id); |
|
|
|
|
|
|
|
|
var file = runTemplateTool("preview-template.ps1", { TemplateId: Number(id) }); |
|
|
document.getElementById("templatePreview").src = file; |
|
|
document.getElementById("templatePreview").src = file; |
|
|
document.getElementById("templateMessage").innerText = |
|
|
document.getElementById("templateMessage").innerText = |
|
|
"Showing the imported snapshot. This preview does not include the campaign footer yet."; |
|
|
"Showing the imported snapshot. This preview does not include the campaign footer yet."; |
|
|
@@ -441,7 +479,7 @@ |
|
|
TestReceived: document.getElementById("confirmReceived").checked |
|
|
TestReceived: document.getElementById("confirmReceived").checked |
|
|
}; |
|
|
}; |
|
|
} |
|
|
} |
|
|
function withCampaignRequest(scriptName, extraArgs) { |
|
|
|
|
|
|
|
|
function withCampaignRequest(scriptName, extraParameters) { |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var folder = fs.BuildPath(projectRoot(), "temp"); |
|
|
var folder = fs.BuildPath(projectRoot(), "temp"); |
|
|
if (!fs.FolderExists(folder)) fs.CreateFolder(folder); |
|
|
if (!fs.FolderExists(folder)) fs.CreateFolder(folder); |
|
|
@@ -454,7 +492,9 @@ |
|
|
stream.WriteText(JSON.stringify(campaignRequest())); |
|
|
stream.WriteText(JSON.stringify(campaignRequest())); |
|
|
stream.SaveToFile(path, 2); |
|
|
stream.SaveToFile(path, 2); |
|
|
stream.Close(); |
|
|
stream.Close(); |
|
|
return runTemplateTool(scriptName, "-RequestPath " + quoted(path) + (extraArgs || "")); |
|
|
|
|
|
|
|
|
var parameters = extraParameters || {}; |
|
|
|
|
|
parameters.RequestPath = path; |
|
|
|
|
|
return runTemplateTool(scriptName, parameters); |
|
|
} finally { |
|
|
} finally { |
|
|
if (stream.State === 1) stream.Close(); |
|
|
if (stream.State === 1) stream.Close(); |
|
|
if (fs.FileExists(path)) fs.DeleteFile(path); |
|
|
if (fs.FileExists(path)) fs.DeleteFile(path); |
|
|
@@ -463,7 +503,7 @@ |
|
|
function reviewCampaign() { |
|
|
function reviewCampaign() { |
|
|
invalidateCampaignReview(); |
|
|
invalidateCampaignReview(); |
|
|
try { |
|
|
try { |
|
|
var data = JSON.parse(withCampaignRequest("review-campaign.ps1", "")); |
|
|
|
|
|
|
|
|
var data = JSON.parse(withCampaignRequest("review-campaign.ps1")); |
|
|
pendingCampaignReview = data; |
|
|
pendingCampaignReview = data; |
|
|
document.getElementById("campaignReview").innerText = |
|
|
document.getElementById("campaignReview").innerText = |
|
|
data.Count + " eligible recipients. From: " + data.From + ". Reply-to: " + |
|
|
data.Count + " eligible recipients. From: " + data.From + ". Reply-to: " + |
|
|
@@ -482,7 +522,7 @@ |
|
|
if (!pendingCampaignReview) return; |
|
|
if (!pendingCampaignReview) return; |
|
|
if (!window.confirm("Send this campaign test to " + pendingCampaignReview.TestTo + "?")) return; |
|
|
if (!window.confirm("Send this campaign test to " + pendingCampaignReview.TestTo + "?")) return; |
|
|
try { |
|
|
try { |
|
|
var result = withCampaignRequest("send-campaign-test.ps1", " -Send"); |
|
|
|
|
|
|
|
|
var result = withCampaignRequest("send-campaign-test.ps1", { Send: true }); |
|
|
campaignTestAccepted = true; |
|
|
campaignTestAccepted = true; |
|
|
document.getElementById("confirmReceived").disabled = false; |
|
|
document.getElementById("confirmReceived").disabled = false; |
|
|
document.getElementById("campaignMessage").innerText = result; |
|
|
document.getElementById("campaignMessage").innerText = result; |
|
|
@@ -501,7 +541,7 @@ |
|
|
if (!window.confirm("Approve " + pendingCampaignReview.Count + |
|
|
if (!window.confirm("Approve " + pendingCampaignReview.Count + |
|
|
" recipients? The campaign will remain paused.")) return; |
|
|
" recipients? The campaign will remain paused.")) return; |
|
|
try { |
|
|
try { |
|
|
var result = withCampaignRequest("approve-campaign.ps1", ""); |
|
|
|
|
|
|
|
|
var result = withCampaignRequest("approve-campaign.ps1"); |
|
|
document.getElementById("campaignMessage").innerText = result; |
|
|
document.getElementById("campaignMessage").innerText = result; |
|
|
invalidateCampaignReview(); |
|
|
invalidateCampaignReview(); |
|
|
refreshStatus(); |
|
|
refreshStatus(); |
|
|
@@ -566,7 +606,7 @@ |
|
|
var folder = fs.BuildPath(projectRoot(), "temp"); |
|
|
var folder = fs.BuildPath(projectRoot(), "temp"); |
|
|
if (!fs.FolderExists(folder)) fs.CreateFolder(folder); |
|
|
if (!fs.FolderExists(folder)) fs.CreateFolder(folder); |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
runTemplateTool("dispatch-control.ps1", "-Action Recover"); |
|
|
|
|
|
|
|
|
runTemplateTool("dispatch-control.ps1", { Action: "Recover" }); |
|
|
dispatchSessionPid = htaProcessId(); |
|
|
dispatchSessionPid = htaProcessId(); |
|
|
dispatchSessionToken = ""; |
|
|
dispatchSessionToken = ""; |
|
|
for (var i = 0; i < 32; i++) |
|
|
for (var i = 0; i < 32; i++) |
|
|
@@ -596,13 +636,13 @@ |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
if (dispatchSessionPath && fs.FileExists(dispatchSessionPath)) |
|
|
if (dispatchSessionPath && fs.FileExists(dispatchSessionPath)) |
|
|
fs.DeleteFile(dispatchSessionPath); |
|
|
fs.DeleteFile(dispatchSessionPath); |
|
|
runTemplateTool("dispatch-control.ps1", "-Action PauseAll"); |
|
|
|
|
|
|
|
|
runTemplateTool("dispatch-control.ps1", { Action: "PauseAll" }); |
|
|
} catch (ignored) { } |
|
|
} catch (ignored) { } |
|
|
} |
|
|
} |
|
|
function refreshDispatchStatus() { |
|
|
function refreshDispatchStatus() { |
|
|
if (!dispatchReady || (dispatchProcess && dispatchProcess.Status === 0)) return; |
|
|
|
|
|
|
|
|
if (!dispatchReady || dispatchProcess) return; |
|
|
try { |
|
|
try { |
|
|
var status = JSON.parse(runTemplateTool("dispatch-control.ps1", "-Action Status")); |
|
|
|
|
|
|
|
|
var status = JSON.parse(runTemplateTool("dispatch-control.ps1", { Action: "Status" })); |
|
|
document.getElementById("sendState").innerText = status.Paused ? |
|
|
document.getElementById("sendState").innerText = status.Paused ? |
|
|
"Paused" : "Running " + status.RunningCampaigns + " campaign(s)"; |
|
|
"Paused" : "Running " + status.RunningCampaigns + " campaign(s)"; |
|
|
document.getElementById("dispatchSummary").innerText = |
|
|
document.getElementById("dispatchSummary").innerText = |
|
|
@@ -619,14 +659,25 @@ |
|
|
if (!dispatchReady) return; |
|
|
if (!dispatchReady) return; |
|
|
try { |
|
|
try { |
|
|
writeHeartbeat(); |
|
|
writeHeartbeat(); |
|
|
|
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
if (dispatchProcess) { |
|
|
if (dispatchProcess) { |
|
|
if (dispatchProcess.Status === 0) return; |
|
|
|
|
|
var output = dispatchProcess.StdOut.ReadAll(); |
|
|
|
|
|
var errors = dispatchProcess.StdErr.ReadAll(); |
|
|
|
|
|
var exitCode = dispatchProcess.ExitCode; |
|
|
|
|
|
|
|
|
if (!fs.FileExists(dispatchProcess.resultPath)) { |
|
|
|
|
|
if (!dispatchProcess.warned && |
|
|
|
|
|
new Date().getTime() - dispatchProcess.startedAt > 60000) { |
|
|
|
|
|
dispatchProcess.warned = true; |
|
|
|
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
|
|
|
"Sending helper has not returned. No further attempts will start until it finishes; pause and review the campaign."; |
|
|
|
|
|
} |
|
|
|
|
|
return; |
|
|
|
|
|
} |
|
|
|
|
|
var finished = dispatchProcess; |
|
|
dispatchProcess = null; |
|
|
dispatchProcess = null; |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
|
|
|
(exitCode === 0 ? "" : "Dispatch error: ") + output + errors; |
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
document.getElementById("dispatchMessage").innerText = finishHiddenTool(finished); |
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
|
|
|
"Dispatch error: " + error.message; |
|
|
|
|
|
} |
|
|
refreshStatus(); |
|
|
refreshStatus(); |
|
|
refreshCampaigns(); |
|
|
refreshCampaigns(); |
|
|
refreshDispatchStatus(); |
|
|
refreshDispatchStatus(); |
|
|
@@ -640,13 +691,8 @@ |
|
|
rows.Close(); |
|
|
rows.Close(); |
|
|
} finally { db.Close(); } |
|
|
} finally { db.Close(); } |
|
|
if (!running) return; |
|
|
if (!running) return; |
|
|
var fs = new ActiveXObject("Scripting.FileSystemObject"); |
|
|
|
|
|
var script = fs.BuildPath(projectRoot(), "tools\\dispatch-once.ps1"); |
|
|
|
|
|
var command = quoted(powerShellHost()) + " -NoProfile -ExecutionPolicy Bypass -File " + |
|
|
|
|
|
quoted(script) + " -ConfigPath " + quoted(fs.BuildPath(projectRoot(), "config.ini")) + |
|
|
|
|
|
" -Send -SessionPid " + dispatchSessionPid + |
|
|
|
|
|
" -SessionToken " + dispatchSessionToken; |
|
|
|
|
|
dispatchProcess = new ActiveXObject("WScript.Shell").Exec(command); |
|
|
|
|
|
|
|
|
dispatchProcess = startHiddenTool("dispatch-once.ps1", { Send: true, |
|
|
|
|
|
SessionPid: dispatchSessionPid, SessionToken: dispatchSessionToken }, false); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
"Dispatch tick failed: " + error.message; |
|
|
"Dispatch tick failed: " + error.message; |
|
|
@@ -654,10 +700,10 @@ |
|
|
} |
|
|
} |
|
|
function dispatchControl(action, campaignId, deliveryId) { |
|
|
function dispatchControl(action, campaignId, deliveryId) { |
|
|
try { |
|
|
try { |
|
|
var args = "-Action " + action; |
|
|
|
|
|
if (campaignId) args += " -CampaignId " + campaignId; |
|
|
|
|
|
if (deliveryId) args += " -DeliveryId " + deliveryId; |
|
|
|
|
|
var result = runTemplateTool("dispatch-control.ps1", args); |
|
|
|
|
|
|
|
|
var parameters = { Action: action }; |
|
|
|
|
|
if (campaignId) parameters.CampaignId = Number(campaignId); |
|
|
|
|
|
if (deliveryId) parameters.DeliveryId = Number(deliveryId); |
|
|
|
|
|
var result = runTemplateTool("dispatch-control.ps1", parameters); |
|
|
document.getElementById("dispatchMessage").innerText = result; |
|
|
document.getElementById("dispatchMessage").innerText = result; |
|
|
refreshCampaigns(); |
|
|
refreshCampaigns(); |
|
|
refreshUncertain(); |
|
|
refreshUncertain(); |
|
|
@@ -693,7 +739,7 @@ |
|
|
if (!window.confirm("Send a test of approved campaign #" + id + |
|
|
if (!window.confirm("Send a test of approved campaign #" + id + |
|
|
" to " + settings.SMTP_TEST_TO + " only?")) return; |
|
|
" to " + settings.SMTP_TEST_TO + " only?")) return; |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
runTemplateTool("send-approved-campaign-test.ps1", "-CampaignId " + id + " -Send"); |
|
|
|
|
|
|
|
|
runTemplateTool("send-approved-campaign-test.ps1", { CampaignId: Number(id), Send: true }); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
document.getElementById("dispatchMessage").innerText = |
|
|
"Approved campaign test failed: " + error.message; |
|
|
"Approved campaign test failed: " + error.message; |
|
|
@@ -750,7 +796,7 @@ |
|
|
var id = document.getElementById("reportCampaign").value; |
|
|
var id = document.getElementById("reportCampaign").value; |
|
|
if (!/^[1-9][0-9]*$/.test(id)) throw new Error("Select a campaign to report"); |
|
|
if (!/^[1-9][0-9]*$/.test(id)) throw new Error("Select a campaign to report"); |
|
|
document.getElementById("reportMessage").innerText = |
|
|
document.getElementById("reportMessage").innerText = |
|
|
runTemplateTool("export-report.ps1", "-CampaignId " + id); |
|
|
|
|
|
|
|
|
runTemplateTool("export-report.ps1", { CampaignId: Number(id) }); |
|
|
} catch (error) { |
|
|
} catch (error) { |
|
|
document.getElementById("reportMessage").innerText = |
|
|
document.getElementById("reportMessage").innerText = |
|
|
"Report export failed: " + error.message; |
|
|
"Report export failed: " + error.message; |
|
|
|