Files
Facilitor/APPL/Shared/Shared.inc
Jos Groot Lipman 48f24f0f61 Merge 2022.3 RC1/2 patches
svn path=/Website/trunk/; revision=57497
2022-10-05 07:43:24 +00:00

2435 lines
89 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<% /*
$Revision$
$Id$
File: shared.inc
Description: Generieke functies die door elke pagina gebruikt worden.
Parameters:
Context: Vanuit ELK asp bestand
Note: Dus gebruik met mate
*/ %>
<%
function CreateFullPath(sPath)
{
if (!fso.FolderExists(sPath))
{
while (!fso.FolderExists(sPath))
{
var sParent = sPath;
while (sParent && !fso.FolderExists(sParent))
{
var sChild = sParent;
var sParent = fso.GetParentFolderName(sChild);
}
if (!sParent)
{
__DoLog("Cannot create folder {0}, parentfolder does not exist.".format(sPath), "#f00");
INTERN_ERROR_BAD_PATH;
}
oFolder = fso.CreateFolder(sChild);
}
}
}
function hasColumn(tableview, columname, datatype)
{
var hascol = null;
var sql = "SELECT data_type FROM user_tab_cols"
+ " WHERE table_name = " + safe.quoted_sql_upper(tableview)
+ " AND column_name = " + safe.quoted_sql_upper(columname);
if (datatype)
sql += " AND data_type = " + safe.quoted_sql_upper(datatype);
var oRs = Oracle.Execute(sql);
if (!oRs.Eof)
hascol = oRs("data_type").Value;
oRs.close();
return hascol;
}
function setWebconfig(folder)
{
if (fso.FolderExists(folder) && !fso.FileExists(folder + "/web.config"))
fso.CopyFile(Server.MapPath(rooturl + '/utils/') + "/web.config", folder + "/web.config", false); // Don't overwrite
}
// In deze functie komen we in ieder geval één keer per dag ('s ochtends als de application pool opstart)
// Doe allerlei housekeeping hier.
// Let op dat niet bekend is welke user toevallig de eerste van de dag is. Daarom onafhankelijk van autorisatie
// Let op dat het wordt aangeroepen vanuit default.inc/loadSET() dus ook iedere keer als een setting wijzigt!
function fclt_daily()
{
FCLTHeader.generateTemplateCss(); // Recreate at least once per day
setWebconfig(Server.MapPath(rooturl + '/temp/')); // geldt voor alle klanten tegelijk
// Het liefst zou ik gewoon de *hele* custfolder beschermen maar er staan wel eens
// (menu)image bestanden die via http worden benaderd.
setWebconfig(Server.MapPath(custpath + "/Export"));
setWebconfig(Server.MapPath(custpath + "/Import"));
setWebconfig(Server.MapPath(custpath + "/Plugins"));
setWebconfig(Server.MapPath(custpath + "/Tasks"));
setWebconfig(Server.MapPath(custpath + "/Xsl"));
// Pseudo overschrijding om aantal gebruikers gisteren te registreren
var sql = "BEGIN fac.fac_perfmon_incr("+S("perfmon_threshold")+", 0); END;"
Oracle.Execute(sql);
// Rotate logfile
rotateLogfile(S("max_logfile_size"));
}
var shared = {
trackaction:
function (paction, pkey, poms) /* paction is something like 'BEZMUT', 'MLDAFM' etc */
{ // noot: trackaction genereert ook eventuele notificaties
var sql = "BEGIN fac.trackaction(" + safe.quoted_sql(paction) + ", " + (pkey>0?pkey:"NULL") + ", " + (user_key>0?user_key:"NULL") + ", NULL, " + safe.quoted_sql(poms, 2000) + "); END;"
Oracle.Execute(sql);
if (paction.substr(0,1) != "#") // # voor '#MLDBEH' betekent 'niet notificeren'
putorders.sendnotifications(pkey, paction);
},
auditfail:
function (poms)
{
var sql = "INSERT INTO fac_auditfail (fac_auditfail_tekst) VALUES (" + safe.quoted_sql(poms, 2000) + ")";
Oracle.Execute(sql);
},
// Keep track of GUI actions, params.daily summarizes per day anonymously
registeraction:
function (pgroup, params)
{
var counter_key = -1;
var flds = [];
var safevals = [];
flds.push("fac_gui_counter_group");
safevals.push(safe.quoted_sql(pgroup));
if (!params.daily)
{
flds.push("prs_perslid_key");
safevals.push(user_key);
}
if (params.truncdate || params.daily)
{
flds.push("fac_gui_counter_date");
safevals.push("TRUNC(SYSDATE)");
}
if (params.info)
{
flds.push("fac_gui_counter_info");
safevals.push(safe.quoted_sql(params.info, 1000));
}
if (params.refkey)
{
flds.push("fac_gui_counter_refkey");
safevals.push(params.refkey);
}
if (!params.daily)
{
var sql = "SELECT faq_s_fac_gui_counter_key.nextval FROM dual";
var oRs = Oracle.Execute( sql );
counter_key = oRs(0).value;
oRs.Close();
flds.push("fac_gui_counter_key");
safevals.push(counter_key);
sql = "BEGIN"
+ " INSERT INTO fac_gui_counter ("+flds.join(", ")+")"
+ " VALUES ("+safevals.join(", ")+");"
+ " EXCEPTION WHEN dup_val_on_index" // Twee keer in dezelfde seconde negeren
+ " THEN "
+ " NULL; "
+ " END;"
Oracle.Execute(sql);
}
else
{
// upsert the daily counter, relies on the unique index
// you might think that update-insert is more efficient (because more often) than insert-update
// JGL: inderdaad, dat is efficienter dus omgedraaid.
var wheres = [];
for (var i=0; i<flds.length; i++) {
wheres.push(flds[i] + "=" + safevals[i]);
}
var sql = "BEGIN"
+ " UPDATE fac_gui_counter SET fac_gui_counter_count = fac_gui_counter_count + 1"
+ " WHERE ("+ wheres.join(" AND ")+");"
+ " IF SQL%ROWCOUNT = 0 THEN"
+ " INSERT INTO fac_gui_counter ("+flds.join(", ")+", fac_gui_counter_count)"
+ " VALUES ("+safevals.join(", ")+", 1);"
+ " END IF;"
+ " END;";
Oracle.Execute(sql);
}
return counter_key;
},
// Verondersteld dat head al is geweest.
simpel_body: function(bodyhtml)
{
Response.Write("<body class='simpelpage'>");
Response.Write(bodyhtml);
Response.Write("</body></html>");
Response.End;
},
// Maak een heel simpele pagina.
// Als DOCTYPE_Disable dan veronderstellen we een JSON-vraag en sturen we JSON terug
// (Anders zou er waarschijnlijk een Ajax Error optreden)
simpel_page: function(bodyhtml, headhtml)
{
function _httpAcceptOnly(httpAccept, type)
{
var httpAccept_arr = httpAccept.split(",");
for (var i in httpAccept_arr)
{
if (httpAccept_arr[i].indexOf("/") == -1 || httpAccept_arr[i].split("/")[1].indexOf(type) != 0)
return false;
}
return true;
}
var httpAccept = String(Request.ServerVariables("HTTP_ACCEPT")).split(";")[0].toLowerCase();
if (typeof mobile == "object" && "simpel_page" in mobile && _httpAcceptOnly(httpAccept, "json") == false)
mobile.simpel_page(bodyhtml);
else
if ((typeof DOCTYPE_Disable != "undefined" && JSON_Result) || _httpAcceptOnly(httpAccept, "json"))
{ // JSON
bodyhtml = bodyhtml.replace(/\<br\>/ig, "\n")
.replace(/\<p\>/ig, "\n")
.replace(/\<\/p\>$/ig, "")
.replace(/\<\/p\>/ig, "\n");
Response.Clear();
Response.Write(JSON.stringify({success: false, message: bodyhtml}));
Response.End;
}
else if (_httpAcceptOnly(httpAccept, "xml"))
{ // XML
var xmlDoc = new ActiveXObject("MSXML2.DOMDocument.6.0");
xmlDoc.appendChild(xmlDoc.createProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""));
var fac_elem = xmlDoc.createElement("facilitor");
var err_elem = xmlDoc.createElement("error");
var err_text = xmlDoc.createTextNode(bodyhtml);
err_elem.appendChild(err_text);
fac_elem.appendChild(err_elem);
xmlDoc.appendChild(fac_elem);
Response.ContentType = "text/xml";
Response.Clear();
Response.Write(xmlDoc.xml);
Response.End;
}
else
{ // HTML
Response.Clear();
Response.Write("<!DOCTYPE html>");
Response.Write("<html class='simpel_page'><head>");
if (typeof FCLTHeader != "undefined")
FCLTHeader.Generate();
else // Poor man styling
Response.Write("<style>* { font-family: Tahoma, Verdana; font-size: 11pt; line-height: 1.4em } </style>");
if (headhtml)
Response.Write(headhtml);
Response.Write("</head>");
shared.simpel_body(bodyhtml);
}
},
internal_error: function (message)
{
shared.simpel_page(L("lcl_internal_error") + " " + toISODateTimeString(new Date()) + "<p>" + safe.html(message) + "</p>");
},
record_not_found: function (html)
{
shared.simpel_page(L("lcl_recnotfound_error") + (html||""));
},
// Delay in milliseconde zonder dat het processor-kracht kost
// Handig als je traag gedrag wilt simuleren
delay: function (ms)
{
var oAbout = new ActiveXObject("SLNKDWF.About");
oAbout.Sleep(ms);
},
// b64 versie levert op volgens rfc4648 zodat de waarde url-safe is
// geen +/ maar -_
// Let op: len is het aantal gewenste karakters, dat zal groter zijn dan het aantal bytes
random: function (len, encoding)
{
len = len || 32;
encoding = encoding || "base64";
switch (encoding)
{
case "base64": bytes = Math.ceil(len * 6 / 8); break;
case "base32": bytes = Math.ceil(len * 5 / 8); break;
case "hex": bytes = len * 4 / 8; break;
default: BAD_RANDOM_ENCODING;
}
try
{
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
var rnd = oCrypto.hex_random(bytes);
switch (encoding)
{
case "base64": rnd = oCrypto.hex2base64(rnd, false, true); break; // no padding, urlsafe
case "base32": rnd = oCrypto.hex2base32(rnd); break;
case "hex": rnd = rnd; break;
default: BAD_RANDOM_ENCODING;
}
}
catch(e)
{ // Minstens versie 4.14 voor random
abort_with_warning("SLNKDWFx64.DLL not properly installed or too old version.\n{0}".format(e.description));
}
return rnd.substr(0, len);
},
isGoodNumber: function(str, intOnly, posOnly, numLen, numDec)
{
var posOnlyStr = (posOnly ? "" : "\\-?");
var numLenStr = (numLen == -1 ? "" : (numDec == -1 ? numLen : (intOnly ? numLen : numLen - numDec)));
var numDecStr = (numDec == -1 ? "" : numDec);
var intOnlyStr = "\\d{1," + numLenStr + "}";
var dblOnlyStr = "\\d{0," + numLenStr + "}[.,]\\d{1," + numDecStr + "}" + "|"
+ "\\d{1," + numLenStr + "}[.,]\\d{0," + numDecStr + "}" ;
var anum = "^"
+ posOnlyStr + "(" + intOnlyStr
+ (intOnly ? "" : "[.,]?" + "|" + dblOnlyStr)
+ ")"
+ "$";
var patt = new RegExp(anum);
return patt.test(str);
},
// Checken of het eenheden selectveld met dagen/uren bij "Acceptatietijd" niet readonly was en wel is meegegeven.
// Als dit eenheden selectieveld readonly was dan wordt deze niet opgeslagen en dan moet de tijdsduur ook niet opgeslagen worden.
// Als 0 dagen/uren dan beide velden leeg maken. Als eenheidsveld aanwezig is, moet ook het tijdsduurveld aangwezig zijn.
add_time_field: function add_time_field(fields, dbsname, frm_tijd, frm_eenheid, track)
{
var dayshours = Request.Form(frm_eenheid).count > 0 && getFParamFloat(frm_tijd, -1) > 0;
if (dayshours)
fields.push({ dbs: dbsname + ".tijdsduur", obj: "MLD_T_UITVOERTIJD", typ: "float", frm: frm_tijd, track: (track? track.tracktijdsduur : null) },
{ dbs: dbsname + ".eenheid", obj: "MLD_T_UITVOERTIJD", typ: "varchar", frm: frm_eenheid, track: (track? track.trackeenheid : null) });
else // Leegmaken
fields.push({ dbs: dbsname + ".tijdsduur", obj: "MLD_T_UITVOERTIJD", typ: "float", val: null, track: (track? track.tracktijdsduur : null) },
{ dbs: dbsname + ".eenheid", obj: "MLD_T_UITVOERTIJD", typ: "varchar", val: null, track: (track? track.trackeenheid : null) });
return fields;
},
// Converteer zo veel mogelijk direct naar goede type
_qssafe: function __qssafe(model, fld, strval)
{
if (fld.toLowerCase() == 'id')
{
if (String(strval).toLowerCase() == "self")
return user_key;
else
return parseInt(strval, 10);
}
if (fld.toLowerCase() == 'limit')
return parseInt(strval, 10);
if (fld.toLowerCase() == 'offset')
return parseInt(strval, 10);
return strval; // NOTE: Rest nog even niet, gaf nog problemen met foreigns (FSN#33730)
// Deze moet blijven werken
// http://uwva.facws001.sg.nl/branch20211/api2/locations.json?district=~Noordwest
var field = model.fields[fld];
if (!field)
return strval;
switch (field.typ)
{
case "float":
return parseFloat(strval.replace(/,/g,"."));
break;
case "key":
case "number":
return parseInt(strval, 10);
break;
case "check":
case "check0":
//val = (Request.Form(formfields[i].frm).count==1)?1:0;
//break;
case "date":
case "datetime":
// Hier zouden we ook de ISO-dates moeten aankunnen?
//val = getFParamDate(formfields[i].frm, null);
//break;
case "memo":
case "varchar":
return strval;
break;
default:
{
return strval;
}
}
return strval;
},
form2json: function _form2json(model)
{
return shared._coll2json(model, Request.Form);
},
qs2json: function _qs2json(model)
{
return shared._coll2json(model, Request.QueryString);
},
tempFolder: function _tempFolder()
{
return Server.MapPath(rooturl + '/temp/' + customerId);
},
_coll2json: function _coll2json(model, pColl) // Vergelijk ook api2.form2JSONdata die er erg op lijkt
{
var filter = {};
for (var i = 1; i <= pColl.Count; i++)
{
var name = pColl.key(i).toLowerCase();
var data = pColl(i);
if (data.Count > 1)
{
filter[name] = [];
for (var j = 1; j <= data.Count; j ++)
filter[name].push(shared._qssafe(model, name, String(data(j))));
}
else
filter[name] = shared._qssafe(model, name, String(data));
}
return filter;
},
stripbbcodes: function (waarde)
{
if (!waarde || typeof waarde != "string") // early exit
return waarde;
if (waarde.indexOf("[") == -1) // snelle goedkope controle
return waarde;
var safepairs = "h1,h2,h3,h4,h5,h6,b,i,u,s,em,strong,small,big,th,td,tr,table,pre,code".split(",");
for (var i = 0; i < safepairs.length; i++)
{
var code = safepairs[i];
var strre = "\\[{0}\\]([\\S\\s]*?)\\[\\/{0}\\]".format(code); // De ? maakt de .* lazy (ipv greedy)
var strnew = "$1";
if (code == "code") // <code> heeft bij ons display: block
strnew = "\n" + strnew + "\n";
var re = new RegExp(strre, "g");
var waarde = waarde.replace(re, strnew);
}
// Checking for [link] url (|optionaltext) [/link]
// or [url] url (|optionaltext) [/url]
var strre = "\\[(link|url)\\]([\\S\\s]*?)\\[\\/(?:\\1)\\]";
var allowedLinkRegex = new RegExp(S("allowedLinkRegex"), "i");
var matched = waarde.match(new RegExp(strre, "gi"));
if (matched != null)
{
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
if (groups)
{
// groups[1] = "link" of "url" (wordt verder niet gebruikt)
// groups[2] = url (|optionaltext)
var regExpResult = groups[2].split("|");
var safe_url = safe.htmlattr(regExpResult[0]);
var url_text = (regExpResult.length == 1 ? regExpResult[0] : regExpResult[1]); // (heeft geen optionaltekst ? url : optionaltext)
if (safe_url.match(allowedLinkRegex))
waarde = waarde.replace(matched[i], url_text);
}
}
}
// Checking for [mention] prs_key | prs_name [/mention] as used in notes
strre = "\\[mention\\](\\d+)\\|(.+?)\\[\\/mention\\]";
var matched = waarde.match(new RegExp(strre, "gi"));
if (matched != null)
{
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
if (groups)
{ // groups[1] = prs_key
// groups[2] = prs_name
waarde = waarde.replace(matched[i], "@" + groups[2]);
}
}
}
/* Checking for [img] src [/img] */
strre = "\\[img\\]([\\S\\s]*?)\\[\\/img\\]";
var allowedImgRegex = new RegExp(S("allowedImgRegex"), "i");
matched = waarde.match(new RegExp(strre, "gi"));
if (matched != null)
{
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
if (groups && groups[1].match(allowedImgRegex))
waarde = waarde.replace(matched[i], "[" + L("lcl_image") + "]");
}
}
return waarde;
},
mld_prefix : function (mld_key, fld) // Prefix voor meldingnummer; je kunt ook "ins_srtdiscipline_omschrijving"
{
var sql = "SELECT " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
+ " , sd.ins_srtdiscipline_prefix"
+ " FROM mld_melding m"
+ ", mld_stdmelding s"
+ ", mld_discipline md"
+ ", ins_srtdiscipline sd"
+ " WHERE mld_melding_key = " + mld_key
+ " AND s.mld_stdmelding_key = m.mld_stdmelding_key"
+ " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
+ " AND md.ins_discipline_key = s.mld_ins_discipline_key";
var oRs = Oracle.Execute(sql);
var result = oRs(fld || "ins_srtdiscipline_prefix").Value || "";
oRs.Close();
return result;
},
opdr_prefix : function (opdr_key, fld) // Prefix voor opdrachtnummer; je kunt ook "ins_srtdiscipline_omschrijving"
{
var sql = "SELECT " + lcl.xsqla('sd.ins_srtdiscipline_omschrijving', 'sd.ins_srtdiscipline_key')
+ " , sd.ins_srtdiscipline_prefix"
+ " FROM mld_opdr mo"
+ ", mld_melding m"
+ ", mld_stdmelding s"
+ ", mld_discipline md"
+ ", ins_srtdiscipline sd"
+ " WHERE mo.mld_opdr_key = " + opdr_key
+ " AND mo.mld_melding_key = m.mld_melding_key"
+ " AND s.mld_stdmelding_key = m.mld_stdmelding_key"
+ " AND sd.ins_srtdiscipline_key = md.ins_srtdiscipline_key"
+ " AND md.ins_discipline_key = s.mld_ins_discipline_key";
var oRs = Oracle.Execute(sql);
var result = oRs(fld || "ins_srtdiscipline_prefix").Value || "";
oRs.Close();
return result;
}
};
if (!Math.sign)
{
Math.sign = function(x)
{
// From: moz://a MDN web docs, Math.sign()
return ((x > 0) - (x < 0)) || +x;
}
}
// Check for parameter pName and return the value
// If not specified return defVal
// If defVal not specified pName a required parameter
function getQParam(pName, defVal)
{
return _get_Param(Request.Querystring, pName, defVal);
}
// Nodig binnen jQuery mobile. Gebruik tegenhanger safe.urlUTF8
function getQParamUTF8(pName, defVal)
{
return unescape(decodeURIComponent(escape(getQParam(pName, defVal))));
}
function getFParam(pName, defVal)
{
return _get_Param(Request.Form, pName, defVal);
}
function hasQParam(pName)
{
return Request.Querystring(pName).Count > 0;
}
function hasFParam(pName)
{
return Request.Form(pName).Count > 0;
}
// Met force wordt een aanwezige maar lege waarde ook afgekeurd
// Met name voor (integer) key's
function _get_Param(pColl, pName, defVal, force)
{
var rq = pColl(pName);
if (rq.count > 0 && (!force || rq(1) !== ""))
return rq(1);
else
{
if (typeof defVal != 'undefined')
return defVal;
else // Error message will get to client and/or IIS logfiles
{
if (String(Request.ServerVariables("REQUEST_METHOD")) == "HEAD")
{
__DoLogForm();
__DoLog("Parameter '" + pName + "' is missing, probably because of unexpected HEAD request", "#FFFF00");
__DoLog("Useragent: " + Request.ServerVariables("HTTP_USER_AGENT"));
__DoLog("Referer: " + Request.ServerVariables("HTTP_REFERER"));
Response.End;
}
else
{
_AiAi("INTERNAL_ERROR, parameter {0} is missing".format(pName));
}
}
}
}
// Check for parameter pName and return the Integer value
// If not specified return defVal
// If defVal not specified pName is a required parameter
// If relaxed==true then return defVal on invalid number
function getQParamInt(pName, defVal, relaxed)
{
return _get_ParamInt(Request.Querystring, pName, defVal, relaxed);
}
// only plain ASCII charachters are allowed: a-z, A-Z and digits
function getQParamSafe(pName, defVal)
{
var txt = _get_Param(Request.Querystring, pName, defVal);
if (txt.match(/[^_a-zA-Z0-9\-]/))
_AiAi("INTERNAL_ERROR, parameter {0} should be a simple string but is: {1}".format(pName, txt));
return txt;
}
// only plain ASCII charachters are allowed: a-z, A-Z and digits
function getFParamSafe(pName, defVal)
{
var txt = _get_Param(Request.Form, pName, defVal);
if (txt.match(/[^_a-zA-Z0-9\-]/))
_AiAi("INTERNAL_ERROR, parameter {0} should be a simple string but is: {1}".format(pName, txt));
return txt;
}
function getFParamInt(pName, defVal, relaxed)
{
return _get_ParamInt(Request.Form, pName, defVal, relaxed);
}
function _get_ParamInt(pColl, pName, defVal, relaxed)
{
var strval = _get_Param(pColl, pName, defVal, true); // force: een lege waarde wordt als afwezig beschouwd
if (strval == "") return defVal;
if (String(strval).toLowerCase() == "self") return user_key;
if (strval == defVal) return defVal;
if (relaxed)
strval = String(strval).replace(/[^0-9]*/, ''); // strip leading non-digits
if (String(strval).substr(0,2)=='0x')
var val = parseInt(strval);
else
var val = parseInt(strval, 10);
if (isNaN(val))
{
if (relaxed)
return defVal;
else
// Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, parameter {0} should be integer but is: {1}".format(pName, strval));
}
else
return val;
}
// Check for parameter pName and return the Float value
// If not specified return defVal
// If defVal not specified pName is a required parameter
// If relaxed==true then return defVal on invalid number
function getQParamFloat(pName, defVal, relaxed)
{
return _get_ParamFloat(Request.Querystring, pName, defVal, relaxed)
}
function getFParamFloat(pName, defVal, relaxed)
{
return _get_ParamFloat(Request.Form, pName, defVal, relaxed)
}
function _get_ParamFloat(pColl, pName, defVal, relaxed)
{
var strval = _get_Param(pColl, pName, defVal);
if (strval == "") return defVal;
if (strval == defVal) return defVal;
var val = parseFloat(strval.replace(/,/g,"."));
if (isNaN(val) || !isFinite(val))
{
if (relaxed)
return defVal;
else
// Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, parameter {0} should be float but is: {1}".format(pName, strval));
}
else
return val;
}
// Check for parameter pName and return the Date value
// If not specified return defVal
// If defVal not specified pName is a required parameter
// defVal can be a date object or null
function getQParamDate(pName, defVal)
{
return _get_ParamDate(Request.Querystring, pName, defVal)
}
function getFParamDate(pName, defVal)
{
return _get_ParamDate(Request.Form, pName, defVal)
}
function _get_ParamDate(pColl, pName, defVal)
{
var val = _get_ParamInt(pColl, pName, -1);
if (val>0 && val<=8640000000000000)
return new Date(val);
if (defVal instanceof Date)
return defVal;
if (defVal === null) // bewust triple===
{
return null;
}
// Error message will get to client and/or IIS logfiles
if (String(Request.ServerVariables("REQUEST_METHOD")) == "HEAD")
{
__DoLog("Parameter '" + pName + "' should be date, probably because of unexpected HEAD request", "#FFFF00");
__DoLog("Useragent: " + Request.ServerVariables("HTTP_USER_AGENT"));
__DoLog("Referer: " + Request.ServerVariables("HTTP_REFERER"));
Response.End;
}
_AiAi("INTERNAL_ERROR, parameter {0} should be date but is: {1}".format(pName, val));
}
// Check for parameter pName and return all values
// Levert een array op, eventueel leeg
// Controleert dat het Integers zijn
// Ondersteunt beide formaten: &key=1&key=2&key=3&key=4 etc.
// en ook: &key=1,2,3,4
function getQParamIntArray(pName, defVal, pAll)
{
return _get_ParamIntArray(Request.Querystring, pName, defVal, pAll)
}
function getFParamIntArray(pName, defVal, pAll)
{
return _get_ParamIntArray(Request.Form, pName, defVal, pAll)
}
function _get_ParamIntArray(pColl, pName, defVal, pAll)
{
var rf = pColl(pName);
var arr = [];
if (rf.count > 0 && rf(1) !== "")
{
var i;
for (i=1; i <= rf.count; i++)
{
if (rf(i).indexOf(",") >= 0)
{
arr = arr.concat(rf(i).split(","));
}
else if (rf(i) != "")
{
arr.push(rf(i));
}
}
// Nu nog conversie/controle naar integers
for (i in arr)
{
if (String(arr[i]).toLowerCase() == "self")
{
arr[i] = user_key;
}
else
{
arr[i] = parseInt(arr[i], 10);
}
if (isNaN(arr[i]))
{
_AiAi("INTERNAL_ERROR, ParamIntArray parameter {0} should be all integer".format(pName));
}
}
if (arr.length == 1 && arr[0] == -1 && !pAll)
arr = []; // *alleen* -1 betekent vaak dat iemand 'alle' gekozen heeft
// dat behandelen we effectief als een leeg array
// Met pAll=true wordt een array met alleen de waarde -1 wel toegestaan.
}
if (arr.length)
return arr;
else
{
if (typeof defVal != 'undefined')
return defVal;
else // Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, ParamIntArray parameter {0} is missing".format(pName));
}
}
// Bij key array de -1 waarde er tussen uit halen.
function getQParamKeyArray(pName, defVal, pAll)
{
var arr = _get_ParamIntArray(Request.Querystring, pName, defVal, pAll)
var index = sharedIndexOf(-1, arr);
if (index > -1) arr.splice(index, 1);
return arr;
}
function getFParamKeyArray(pName, defVal, pAll)
{
var arr = _get_ParamIntArray(Request.Form, pName, defVal, pAll)
var index = sharedIndexOf(-1, arr);
if (index > -1) arr.splice(index, 1);
return arr;
}
// Bij string array de "-1" waarde er tussen uit halen.
function getQParamStringArray(pName, defVal, pAll)
{
var arr = _get_ParamArray(Request.Querystring, pName, defVal, pAll)
var index = sharedIndexOf("-1", arr);
if (index > -1) arr.splice(index, 1);
return arr;
}
function getFParamStringArray(pName, defVal, pAll)
{
var arr = _get_ParamArray(Request.Form, pName, defVal, pAll)
var index = sharedIndexOf("-1", arr);
if (index > -1) arr.splice(index, 1);
return arr;
}
function getQParamFloatArray(pName, defVal, pAll)
{
return _get_ParamFloatArray(Request.Querystring, pName, defVal, pAll)
}
function getFParamFloatArray(pName, defVal, pAll)
{
return _get_ParamFloatArray(Request.Form, pName, defVal, pAll)
}
function _get_ParamFloatArray(pColl, pName, defVal, pAll)
{
var rf = pColl(pName);
var arr = [];
if (rf.count > 0 && rf(1) !== "")
{
var i;
for (i=1; i <= rf.count; i++)
{
if (rf(i).indexOf(",") >= 0)
{
arr = arr.concat(rf(i).split(","));
}
else if (rf(i) != "")
{
arr.push(rf(i));
}
}
// Nu nog conversie/controle naar floats
for (i in arr)
{
if (String(arr[i]).toLowerCase() == "self")
{
arr[i] = user_key;
}
else
{
arr[i] = parseFloat(arr[i], 10);
}
if (isNaN(arr[i]))
{
_AiAi("INTERNAL_ERROR, ParamFloatArray parameter {0} should be all float".format(pName));
}
}
if (arr.length == 1 && arr[0] == -1 && !pAll)
arr = []; // *alleen* -1 betekent vaak dat iemand 'alle' gekozen heeft
// dat behandelen we effectief als een leeg array
// Met pAll=true wordt een array met alleen de waarde -1 wel toegestaan.
}
if (arr.length)
return arr;
else
{
if (typeof defVal != 'undefined')
return defVal;
else // Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, ParamFloatArray parameter {0} is missing".format(pName));
}
}
// Check for parameter pName and return all values
// Levert een array op, eventueel leeg
// Als de xxxIntxxx variant maar dan zonder controle dat het Integers zijn
// Ondersteunt beide formaten: &key=E&key=I&key=L&key=A etc.
// en ook: &key=E,I,L,A
// Bij nosplit wordt alleen de eerste ondersteund
function getQParamArray(pName, defVal, nosplit)
{
return _get_ParamArray(Request.Querystring, pName, defVal, nosplit)
}
function getFParamArray(pName, defVal, nosplit)
{
return _get_ParamArray(Request.Form, pName, defVal, nosplit)
}
function _get_ParamArray(pColl, pName, defVal, nosplit)
{
var rf = pColl(pName);
if (rf.count > 0 && rf(1) !== "")
{
var arr = [];
var i;
for (i=1; i <= rf.count; i++)
{
if (!nosplit && rf(i).indexOf(",") >= 0)
{
arr = arr.concat(rf(i).split(","));
}
else
arr.push(rf(i));
}
return arr;
}
else
{
if (typeof defVal != 'undefined')
return defVal;
else // Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, ParamArray parameter {0} is missing".format(pName));
}
}
// Check for parameter pName and return all values
// Levert een array op, eventueel leeg
// Controleert dat het Datums zijn
// Ondersteunt beide formaten: &key=1&key=2&key=3&key=4 etc.
// en ook: &key=1,2,3,4
function getQParamDateArray(pName, defVal)
{
return _get_ParamDateArray(Request.Querystring, pName, defVal)
}
function getFParamDateArray(pName, defVal)
{
return _get_ParamDateArray(Request.Form, pName, defVal)
}
function _get_ParamDateArray(pColl, pName, defVal)
{
var rf = pColl(pName);
if (rf.count > 0)
{
var arr = [];
var i;
for (i=1; i <= rf.count; i++)
{
if (rf(i).indexOf(",") >= 0)
{
arr = arr.concat(rf(i).split(","));
}
else if (rf(i) != "")
{
arr.push(rf(i));
}
}
// Nu nog conversie/controle naar integers
for (i in arr)
{
arr[i] = new Date(parseInt(arr[i], 10));
if (!(arr[i] instanceof Date || arr[i] === null)) // bewust triple===
{
// Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, parameter {0} should be a date Array".format(pName));
}
}
return arr;
}
else
{
if (typeof defVal != 'undefined')
return defVal;
else // Error message will get to client and/or IIS logfiles
_AiAi("INTERNAL_ERROR, ParamDateArray parameter {0} is missing".format(pName));
}
}
// Usage: "Wilt U melding {0} afmelden?".format(12345)
// Localscripts/iface.js heeft de clientside versie
String.prototype.format = function()
{
var formatted = this;
for (var i = 0; i < arguments.length; i++)
{
if (typeof arguments[i] == "string")
arguments[i] = arguments[i].replace(/\$/g, '$$$$');
var regexp = new RegExp('\\{'+i+'\\}', 'gi');
formatted = formatted.replace(regexp, arguments[i]);
}
return formatted;
};
// lijst is een array van parameter namen ["loc_key", "geb_key", "test"]
// params is optioneel een hash { loc_key: 345, geb_key: 34 }
// (zonder params wordt QueryString genomen)
// resultaat: "&loc_key=345&geb_key=34&test=1&test=2"
function buildTransitParam(lijst, params)
{
var result = "";
if (typeof lijst == "string")
lijst = lijst.split(",");
for (var i = 0; i < lijst.length; i++)
{
var itm = lijst[i];
if (params && params[itm]) // meegegeven
result = result + "&" + itm + "=" + Server.URLencode(params[itm]);
else
{
var urlparams = Request.QueryString(itm);
if (urlparams.count > 0)
{ // Waarde is meegegeven, dan ook doorgeven.
// Voeg elke waarde als aparte string waarde toe.
for (var j = 1; j <= urlparams.count; j++)
{
result += "&" + itm + "=" + Server.URLencode(urlparams(j));
}
}
}
}
return result;
}
// Op een XSS veilige manier de complete QueryString door kunnen geven
function transitQS()
{
var result = "";
for (var i = 1; i <= Request.QueryString.count; i++)
{
var itm = Request.QueryString.key(i);
var urlparams = Request.QueryString.item(i);
var hasHMAC = Request.QueryString("hmac").Count > 0;
var safe_itm;
var safe_urlparam;
// Nu de waarde of waarden goed uitlezen.
// urlparams kan uit meerdere waarden bestaan. Als string staan er dan extra spaties achter de komma's.
// Voeg elke waarde als aparte string waarde toe.
for (var j = 1; j <= urlparams.count; j++)
{
if (hasHMAC)
{
safe_itm = itm; // anders wordt een underscore in &mld_key een %5F en klopt de hmac niet meer
safe_urlparam = urlparams(j);
}
else
{
safe_itm = Server.URLencode(itm);
safe_urlparam = Server.URLencode(urlparams(j));
}
result += "&" + safe_itm + "=" + safe_urlparam;
}
}
return result;
}
function padout(number) { return (number < 10) ? "0" + number : number; }
function oRaAsUserTZ(prefix, varName, isGroupClause)
{
if (prefix != "")
prefix += ".";
/////
// Returns;
// for GROUP BY Clause: the same prefix + "." + varName
// for SELECT Clause: the same prefix + "." + varName with correct syntax and an Alias as + "_tz"
/////
if (Session("time_zone") == S("fac_server_timezone"))
return (isGroupClause ? "" : " , ")
+ prefix + varName
+ (isGroupClause ? "" : " " + varName + "_tz");
/////
// Returns;
// for GROUP BY Clause: syntax for converted timezone
// for SELECT Clause: syntax for converted timezone with comma for SELECT Clause, named: [varName + "_tz"]
/////
return (isGroupClause ? "" : " , ")
+ "CAST(FROM_TZ(CAST(" + prefix + varName + " AS TIMESTAMP), TO_CHAR (SYSTIMESTAMP, 'tzr')) AT TIME ZONE SESSIONTIMEZONE AS DATE)"
+ (isGroupClause ? "" : " " + varName + "_tz");
}
function getServerHour(h)
{
var tempDate = new Date();
tempDate.setHours(h);
tempDate = toServerTimeZone(tempDate);
return tempDate.getHours();
}
function getUserHour(h)
{
var tempDate = new Date();
tempDate.setHours(h);
tempDate = toUserTimeZone(tempDate);
return tempDate.getHours();
}
// User timezone = Session("time_zone")
// Server timezone = S("fac_server_timezone")
function toUserTimeZone(thisDate)
{
return convertTimeZone(thisDate, S("fac_server_timezone"), Session("time_zone"));
}
function toServerTimeZone(thisDate)
{
return convertTimeZone(thisDate, Session("time_zone"), S("fac_server_timezone"));
}
function convertTimeZone(thisDate, fromTZ, toTZ)
{
if (!fromTZ || !toTZ || fromTZ.toUpperCase() == toTZ.toUpperCase())
return thisDate;
var sql = "SELECT CAST ("
+ "FROM_TZ (CAST ( "+thisDate.toSQL(true)+" AS TIMESTAMP), "+safe.quoted_sql(fromTZ)+")"
+ " AT TIME ZONE "+safe.quoted_sql(toTZ)+" AS DATE)"
+ " AS newDate"
+ " FROM DUAL";
var oRs = Oracle.Execute(sql);
thisDate = new Date(oRs("newDate").value);
oRs.close();
return thisDate;
}
// This function should only be used to format display,
// never as part of a computation.
function toTimeString(jsDate, bWithSeconds, noConvert)
{
if (jsDate===null)
return "";
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
jsDate = new Date(jsDate.value);
if (typeof jsDate == "date") // een oRs("datum").value
jsDate = new Date(jsDate);
if (typeof jsDate == "number") // 8.5 voor 08:30
{
if (jsDate < 0 || jsDate > 24)
return "";
var hh = Math.floor(jsDate);
var mm = (jsDate*60) % 60;
jsDate = new Date();
jsDate.setHours(hh,mm,0,0);
}
if (!jsDate)
return "";
if (!noConvert)
jsDate = toUserTimeZone(jsDate);
ret = padout(jsDate.getHours()) + ":" + padout(jsDate.getMinutes());
if (bWithSeconds) ret += ":" + padout(jsDate.getSeconds());
return ret;
}
function toDateString(jsDate, noDay, pretty, noConvert)
{
var resstr = "";
var today = new Date().midnight();
var yesterday = (new Date(today))
yesterday.setDate(today.getDate()-1);
var tomorrow = (new Date(today));
tomorrow.setDate(today.getDate()+1);
if (jsDate===null)
return "";
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
jsDate = new Date(jsDate.value);
if (typeof jsDate == "date") // een oRs("datum").value
jsDate = new Date(jsDate);
if (!jsDate)
return "";
if (!noConvert)
jsDate = toUserTimeZone(jsDate);
// Ik wil graag, alleen als parameter friendly?, voor de datums gisteren, vandaag en morgen de tekst Gisteren, Vandaag en Morgen opleveren
// Voor lijsten/sortering is dat vaak niet handig, maar soms is het veel begrijpelijker. Als de mogelijkheid er is, kunnen we
// geleidelijk de toepassing uitbreiden. In Lopende zaken op de portal om mee te beginnen.
if (pretty && jsDate.midnight().getTime() == today.getTime())
resstr = L("lcl_date_today");
else if (pretty && jsDate.midnight().getTime() == yesterday.getTime())
resstr = L("lcl_date_yesterday");
else if (pretty && jsDate.midnight().getTime() == tomorrow.getTime())
resstr = L("lcl_date_tomorrow");
else
resstr = (noDay?"":calendar_names.daysMin[jsDate.getDay()] + " ") +
padout(jsDate.getDate()) + "-" + padout(jsDate.getMonth() + 1) + "-" + padout(jsDate.getFullYear());
return resstr;
}
function toDateTimeString(jsDate, bWithSeconds, noDay, prettyday, noMidnight)
{
if (jsDate===null)
return "";
if (typeof jsDate == "object" && jsDate.type == 135/*adDBTimeStamp, oRs("datum")*/)
jsDate = new Date(jsDate.value);
if (typeof jsDate == "date") // een oRs("datum").value
jsDate = new Date(jsDate);
jsDate = toUserTimeZone(jsDate);
if (noMidnight && jsDate.getTime() == jsDate.midnight().getTime())
return toDateString(jsDate, noDay, prettyday, true)
else
return toDateString(jsDate, noDay, prettyday, true) + " " + toTimeString(jsDate, bWithSeconds, true)
}
// vertaalt een CSS-achtige color naar een pure hexcode van 6 posities
// mag naar hartelust uitgebreid worden. Typische toepassing is het sanitizen
// van een kleur uit de database of setting naar een gebruik waar zuivere hexcode nodig is.
// Die mag dan weer met een parseInt,16 worden omgezet naar decimaal als je zou willen
function toHexValue(colorString, params)
{
params = params || {};
colorString = colorString || "010101";
var retval;
if (colorString && colorString.substring(0,1) == "#")
retval = colorString.substring(1);
else
retval = colorString;
if (params.autobackground)
{
var R = parseInt(retval.substr(0, 2), 16);
var G = parseInt(retval.substr(2, 2), 16);
var B = parseInt(retval.substr(4, 2), 16);
if (Math.pow(255.0 - R,2) +
Math.pow(255.0 - G,2) +
Math.pow(255.0 - B,2) >
Math.pow(R, 2.0) +
Math.pow(G, 2.0) +
Math.pow(B, 2.0)) // dark
{
retval += ",FEFEFE,FF";
}
else
{
retval += ",010101,FF";
}
}
return retval;
}
// Zie document"z:\Project\Sm44\DOC\Intern\Facilitor5i\Facilitor 5i Quotes en Escape.doc"
safe = {
// getal 0 blijft 0
nvl: function (x)
{
if (x == null)
return "";
else
return x;
},
// Bijvoorbeeld <textarea>< % =safe.textarea(waarde)% ></textarea>
textarea: function(waarde)
{
return Server.HTMLEncode(safe.nvl(waarde));
},
// Bijvoorbeeld <div class='fclthtml'>< % =safe.fclthtml(omschr)% ></div>
// We ondersteunen bb-codes die 1-op-1 naar html zijn om te zetten
// Let op: deze functie lijkt veel op default.xsl/safe.fclthtml
// Pas die eventueel ook aan
fclthtml: function (waarde, params)
{
if (!waarde) // early exit
return "";
params = params || {};
var safehtml = safe.html(waarde); // Let op: vervangt *alle* \n door <br>. Dat gaan we deels later nog terugdraaien
// We hebben het wel *nodig* omdat .* niet over meerdere regels werkt (hoewel dat
// weer oplosbaar schijnt te zijn met [\s\S])
// Eerst de complexere bb-tags;
// Checking for [link] url (|optionaltext) [/link]
// or [url] url (|optionaltext) [/url]
var strre = "\\[(link|url)\\](.*?)\\[\\/(?:\\1)\\]";
var allowedLinkRegex = new RegExp(S("allowedLinkRegex"), "i");
var matched = waarde.match(new RegExp(strre, "gi"));
if (matched != null)
{
var url = "";
var label = "";
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
if (groups)
{
// groups[1] = "link" of "url" (wordt verder niet gebruikt)
// groups[2] = url (|optionaltext)
var result = groups[2].split("|");
if (result.length > 0)
{
var safe_url = safe.htmlattr(result[0]);
if (result.length > 2)
{
result.shift();
label = result.join("|");
}
else if (result.length == 2)
label = result[1];
else
label = result[0];
if (safe_url.match(allowedLinkRegex))
{
if (typeof mobile == "undefined")
safehtml = safehtml.replace(safe.html(matched[i]), "<a href=\"" + safe_url + "\" target=\"_blank\" rel=\"noopener noreferrer\">" + safe.fclthtml(label) + "</a>");
else
safehtml = safehtml.replace(safe.html(matched[i]), "<object><a href=\"" + safe_url + "\" target=\"_blank\" rel=\"noopener noreferrer\">" + safe.fclthtml(label) + "</a></object>");
}
}
}
}
}
if (params.mention)
{ // Checking for [mention] prs_key | prs_name [/mention] as used in notes
strre = "\\[mention\\](\\d+)\\|(.+?)\\[\\/mention\\]";
var matched = waarde.match(new RegExp(strre, "gi"));
if (matched != null)
{
var prs_key = -1;
var prs_name = "";
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i"));
if (groups) // Zonder 'g'lobal-flag
{ // groups[1] = prs_key
// groups[2] = prs_name
var prs_key = parseInt(groups[1], 10);
if (groups.length > 2)
safehtml = safehtml.replace(safe.html(matched[i]), "<span class='details' onclick='iface.persoonDetails(null, null, " + prs_key + ")'>@" + safe.html(groups[2]) + "</span>");
}
}
}
}
/* Checking for [img] src [/img] */
strre = "\\[img\\](.*?)\\[\\/img\\]";
var allowedImgRegex = new RegExp(S("allowedImgRegex"), "i");
matched = safehtml.match(new RegExp(strre, "gi"));
if (matched != null)
{
for (var i = 0; i < matched.length; i++)
{
var groups = matched[i].match(new RegExp(strre, "i")); // Zonder 'g'lobal-flag
if (groups)
{
var safe_url = safe.htmlattr(groups[1]);
if (safe_url.match(allowedImgRegex))
safehtml = safehtml.replace(matched[i], "<img alt='" + L("lcl_photos") + "' src=\"" + safe_url + "\" class=\"customImg\">");
}
}
}
// En nu de simpelere bb-tags;
// Als je safepairs hieronder aanpast, moet dat ook in stripbbcodes gebeuren
var safepairs = "h1,h2,h3,h4,h5,h6,b,i,u,s,em,strong,small,big,th,td,tr,table,pre,code".split(",");
for (var i = 0; i < safepairs.length; i++)
{
var code = safepairs[i];
var strre = "\\[{0}\\](.*?)\\[\\/{0}\\]".format(code); // De ? maakt de .* lazy (ipv greedy)
var strnew = "<" + code + ">$1</" + code + ">";
var re = new RegExp(strre, "g");
safehtml = safehtml.replace(re, strnew);
}
if (params.mldlink)
var safehtml = safe.mldlinkhtml(safehtml);
// Nu de <br>'s binnen de tabel terugzetten. Let op dat ze *binnen* <td>'s weer wel moeten blijven
// TODO: Kan dit beter?
if (safehtml.indexOf("<table>") > -1)
{
var tablepairs = "th,td,tr,table".split(",");
for (var i = 0; i < tablepairs.length; i++)
{
var code = tablepairs[i];
var re = new RegExp("<{0}>(\r<br>)+".format(code), "g");
safehtml = safehtml.replace(re, "<" + code + ">");
re = new RegExp("</{0}>(\r<br>)+".format(code), "g");
safehtml = safehtml.replace(re, "</" + code + ">");
}
}
// Nu alle <br>'s binnen <pre> terugzetten
var matches = safehtml.match(/<pre(?:.*?)>(?:.*?)<\/pre>/g);
if (!matches)
matches = safehtml.match(/<code(?:.*?)>(?:.*?)<\/code>/g);
if (matches)
{
var len = matches.length;
var i;
for (i = 0; i < len; i++)
{
var pre = matches[i];
pre = pre.replace(/<br(?:.*?)>/g, '\n');
safehtml = safehtml.replace(matches[i], pre);
}
}
return safehtml;
},
mldlinkhtml: function (safehtml)
{
if (!S("mld_autolink_regexp")) /// (?:(?:melding [A-Z]*)|(?:[A-Z]*\#[A-Z]*))(\d*)
return safehtml;
var safehtml = safehtml.replace(new RegExp(S("mld_autolink_regexp"), "ig"),
(typeof mobile == "undefined"
? "<span class='details' onclick='FcltMgr.openDetail(&quot;appl/mld/mld_melding.asp?mld_key=$1&amp;&quot;, { reuse: true })'>$&</span>"
: "<span class='details' data-ajax='false' onclick='javascript:document.location.href=\"./melding.asp?mld_key=$1\";return false;'>$&</span>"));
return safehtml;
},
notehtml: function(waarde)
{
return safe.fclthtml(waarde, { "mldlink": true, "mention": true });
},
// Bijvoorbeeld <div>< % =safe.html(omschr)% ></div>
html: function (waarde)
{
return Server.HTMLEncode(safe.nvl(waarde)).replace(/\n/g, "<br>");
},
// bijvoorbeeld <input value="< % =safe.htmlattr(waarde) % >">
htmlattr: function (waarde)
{
return Server.HTMLEncode(safe.nvl(waarde)).replace(/\'/g,'&#39;').replace(/\"/g,'&#34;'); // ' syntax highlight correctie
},
// bijvoorbeeld queuemail.asp?subject=" + safe.url(subject)
url: function (waarde)
{
return Server.URLencode(safe.nvl(waarde));
},
urlUTF8: function (waarde) // Nodig binnen jQuery mobile. Gebruik tegenhanger getQParamUTF8
{
return encodeURIComponent(safe.nvl(waarde));
},
// Altijd quotes er om, we verdubbelen interne
// CR+LF binnen een waarde maken we alleen LF van
csv: function (waarde)
{
if (waarde==null)
return "";
return "\"" + String(waarde).replace(/\x0D\x0A/g,'\x0A').replace(/\"/g,'""') + "\""; // " syntax highlight correctie
},
// Levert een getal op als string met een komma of een punt, afhankelijk van de
// decimaal scheider die de gebruiker op zijn eigen PC heeft ingesteld
// Merk op: géén 1000-separator, dat is te lastig
// Te gebruiken voor readonly presentatie van bedragen
displayfloat: function (fnum, decimals, trimZeros)
{
if (fnum == null)
return "";
if (typeof decimals == "undefined")
decimals = 2;
fnum = fnum.toFixed(decimals);
var waarde2 = (1.5).toLocaleString(); // Eventueel gewenste komma, dank zij LCID gezet in appl\FAC\facilitor.inc
fnum = fnum.substring(0, fnum.length - decimals - 1) + waarde2.substring(2, 1) + fnum.substring(fnum.length - decimals);
if (trimZeros)
{
while (fnum.substring(fnum.length-1) == "0")
fnum = fnum.substring(0, fnum.length-1);
if (fnum.substring(fnum.length-1) == waarde2.substring(2, 1))
fnum = fnum.substring(0, fnum.length-1);
}
return fnum;
},
// Levert een getal op als string met een komma of een punt, afhankelijk van de
// decimaal scheider die de gebruiker op zijn eigen PC heeft ingesteld
// Inclusief 1000-separator (Ook afhanklijk van de gebruiker)
// Te gebruiken voor readonly presentatie van bedragen
// Accepteert Number of String met 0 of 1 punt als decimaal scheider. (geen komma's dus)
showFloat: function (fnum, decimals, trimZeros)
{
if (fnum == null || isNaN(fnum))
return fnum;
if (typeof decimals == "undefined" || isNaN(decimals))
decimals = 2; // default = 2
// Maak er een String van op 2 decimalen, en rond alvast op de juiste decimaal af
var factor = Math.pow(10, decimals);
fnum = Math.round(fnum*factor)/factor;
fnum = fnum.toLocaleString();
// Trim de onnodige decimalen
if (decimals == 1)
fnum = fnum.substring(0, fnum.length-1);
else if (decimals == 0)
fnum = fnum.substring(0, fnum.length-3);
// Trim de evt. nullen
var decimalSign = (1.5).toLocaleString().substring(2, 1); // Eventueel gewenste komma, dank zij LCID gezet in appl\FAC\facilitor.inc
if (trimZeros && decimals > 0)
{
while (fnum.substring(fnum.length-1) == "0")
fnum = fnum.substring(0, fnum.length-1);
if (fnum.substring(fnum.length-1) == decimalSign)
fnum = fnum.substring(0, fnum.length-1);
}
return fnum;
},
// luxe variant: gewenste punt/komma en ook duizendscheiders
curr: function (waarde, nocents)
{
return safe.showFloat(waarde, (nocents ? 0 : 2), false);
},
// Editable willen we er echt geen duizend-scheiders in hebben
// Die zijn namelijk heel moeilijk terug te converteren naar number
// Te gebruiken voor bewerkbare velden met bedragen
editablefloat: function(fnum, decimals)
{
return safe.displayfloat(fnum, decimals); // die heeft toch geen duizend-scheiders
},
curreditable: function (waarde)
{
return safe.editablefloat(waarde, 2);
},
// FcltMgr.alert("< % =safe.jsstring(waarde) % >")
// </script> is ook funest!
jsstring: function (waarde)
{
return (safe.nvl(waarde)).replace(/\\/g,'\\\\').replace(/\n/g,'\\n')
.replace(/\r/g,'').replace(/\'/g,'\\x27').replace(/\"/g,'\\x22')
.replace(/\</g, '\\x3C').replace(/\>/g, '\\x3E'); // ' syntax highlight correctie
},
// var S("res_t1")=< % =safe.jsfloat(S("res_t1"))% >
jsfloat: function (fnum)
{
return(String(fnum)).replace(',','.');
},
quoted_sql: function (tekst, maxlen) // maxlen is optioneel
{
if (tekst == null)
return "NULL";
if (!maxlen)
maxlen = 4000;
// Haal alle lage bytes (muv TAB (x09), LF (x0A) en CR (x0D)) er uit. Die representeren
// geen geldig karakter in Windows-1252 of iso-8859. Ook in UTF-8 staan ze niet voor
// tekst, mochten we dat ooit willen gaan ondersteunen.
// Voor ultieme veiligheid ook maar de hoge unicodes er uit? Neen, EURO is ten slotte
// ook een 'hoge' unicode
tekst = tekst.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]+/g, "?");
tekst = tekst.substr(0, maxlen);
// FSN#35288: '{' naar CHR(123) voorkomt Unspecified Error
return "'" + tekst.replace(/\'/g,"''").replace(/\{/g,"'||CHR(123)||'") + "'"; // " syntax highlight correctie
},
qL: function (p_lcl, params)
{
return safe.quoted_sql(L(p_lcl, params));
},
quoted_sql_join: function (tekstarr, toupper) // Vooral voor IN () clausules met tekstwaardes
{
if (!tekstarr || !tekstarr.length)
return "NULL";
var safearr = [];
for (var i = 0; i < tekstarr.length; i++)
{
safearr.push(toupper? safe.quoted_sql_upper(tekstarr[i]) : safe.quoted_sql(tekstarr[i]))
}
return safearr.join(", ");
},
quoted_sql_upper: function (tekst, maxlen)
{
if (tekst == null)
return "NULL";
return safe.quoted_sql(tekst.toUpperCase(), maxlen);
},
quoted_sql_wild: function (tekst, maxlen)
{
if (tekst == null)
return "NULL";
return safe.quoted_sql(tekst.toUpperCase().replace(/\*/g, "%"), maxlen);
},
quoted_sql_wild2: function (tekst)
{
if (tekst == null)
return "NULL";
var zoektekst = tekst.toUpperCase();
switch (S("use_wildcard_with_suggests"))
{
case 0: break; // geen wildcard gebruiken
case 1: zoektekst = zoektekst + "%"; break;
case 2: zoektekst = "%" + zoektekst + "%"; break;
}
return safe.quoted_sql(zoektekst.replace(/\*/g, "%"));
},
// converteer alle waarden in arr naar integer.
// waar dat niet lukt worden ze gewoon verwijderd(?)
int_array: function (arr)
{
var safe_arr = [];
for (var i = 0; i < arr.length; i++)
{
var v = parseInt(arr[i], 10);
if (!isNaN(v))
safe_arr.push(v);
}
return safe_arr;
},
filename: function (naam) // geen 'lage' karakters en geen (back)slashes, *,%,<,>, '"', ':', ';' '?' and '|' of '+'
{
return naam.replace(/[\x00-\x1F|\/|\\|\*|\%\<\>\"\:\;\?\|\+]+/g, "_"); // " syntax highlight correctie
},
UNC: function (filepath) // ADODB.Stream SaveToFile vereist backslash als flexfilespath naar een UNC-share wijst
{
return filepath.replace(/\//g, "\\");
},
UserContext: function ()
{
try
{
var _oAbout = Server.CreateObject('SLNKDWF.About');
return "UserContext: " + _oAbout.UserContext;
}
catch (e)
{
return "UserContext: no SLNKDWF.About " + e.description;
}
}
}
function abort_with_warning(warning, code)
{
if (Request.QueryString("api2").Count > 0)
{
code = code || 500;
var data = { error: { code: code,
message: warning
}
};
var format = Request.QueryString("format");
if (format == "xml")
{
Response.ContentType = "text/xml";
var xml_antwoord = api2_rest.json2xml([data.error], { records_name: "errors", record_name: "error"}, true);
Response.Write(xml_antwoord.xml);
}
else if (format == "html")
{
Response.ContentType = "text/html";
var str_antwoord = "<!DOCTYPE html><html><head></head><body><pre>"
+ Server.HTMLEncode(JSON.stringify(data, null, 2))
+ "</pre></body></html>";
Response.Write(str_antwoord);
}
else
{
Response.ContentType = "application/json";
Response.Write(JSON.stringify(data, null, 2));
}
var codestr = String(code);
if (typeof code == "number")
{
var codestr = { 400: "Bad request",
403: "Forbidden",
404: "Not Found",
422: "Unprocessable Entity" }[code];
if (codestr)
code = code + " " + codestr;
}
Response.Status = code;
Response.End;
}
else if (JSON_Result)
{
Response.Write(JSON.stringify({ warning: warning, keepForm: true }));
}
else
{
var pad = String(Request.ServerVariables("PATH_INFO"));
pad = pad.substring(rooturl.length+1).toLowerCase();
if (!pad || pad == "default.asp") // warning *gegenereerd* door de root-pagina
{ // is allemaal veel te complex
shared.simpel_page(warning);
}
else
{
%>
<html>
<head>
<% FCLTHeader.Generate() %>
<script>
$(function () {
FcltMgr.closeDetail(window, { warning: "<%=safe.jsstring(warning)%>",
keepForm: true
});
});
</script>
</head>
<body>
</body>
</html>
<%
}
}
Response.End
}
var protectHMAC =
{
// Alleen geschikt als tijdelijk geheim, doorgaans wordt
// IIS elke nacht gerecycled en dan zijn we deze kwijt
getProtectSecret: function ()
{
var appsecret = Application(customerId + "_protectsecret");
if (typeof appsecret == "undefined")
{
appsecret = shared.random(32);
Application.Lock();
Application(customerId + "_protectsecret") = appsecret;
Application.UnLock();
}
return appsecret;
},
create: function(str, params)
{
params = params || {};
params.sleutel = params.sleutel || protectHMAC.getProtectSecret();
var ts = String(Math.round((new Date).getTime() / 1000));
var data = ts + ":" + str
__Log("hmacdata: " + data);
//__Log("sleutel: "+ params.sleutel);
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
var sig = oCrypto.hex_hmac_sha1(params.sleutel, data);
var hmac = oCrypto.hex2base64(sig, false, true); // no padding, urlsafe
oCrypto = null; // Caching klinkt leuk maar Oracle sessies blijven langer hangen?
return ts+":"+hmac;
},
verify: function (str, hmac, params)
{
params = params || {};
params.expire = params.expire || 720;
var expTime = new Date;
expTime.setMinutes(expTime.getMinutes()-params.expire); // max expire in het verleden
var future = new Date;
future.setMinutes(future.getMinutes() + 3); // Over 3 minuten begint de toekomst :-)
// Voorkomt misbruik tijdens zomer/wintertijd wissel
var hmacArr = hmac.split(":");
if (hmacArr.length != 2 ||
hmacArr[0].length != 10 || // 10 cijfers timestamp
hmacArr[1].length < 26 || // HMAC_SHA1 is 160bit --> 20 byte --> 20/3*4 is 26 of 27 base64 karakters
hmacArr[1].length > 27)
{
__DoLog("Bad HMAC syntax: {0}".format(hmac), "#ff0000");
shared.internal_error("Bad HMAC syntax"); // Net iets minder erg dan een AiAi
}
var createTimeInt = parseInt(hmacArr[0],10);
var createTime = new Date(createTimeInt*1000);
if (!createTimeInt || !createTime || createTime < expTime || createTime > future)
{
createTime.setMinutes(createTime.getMinutes() + params.expire);
__Log("HMAC: Te laat: je had voor {0} moeten zijn.".format(toISODateTimeString(createTime, true)));
if (params.relaxed)
return false;
else
{
__DoLog("HMAC: Te laat: je had voor {0} moeten zijn.".format(toISODateTimeString(createTime, true)));
shared.simpel_page(L("lcl_hmac_late"));
}
}
__Log("testing hmacdata: " + str);
params.sleutel = params.sleutel || protectHMAC.getProtectSecret();
//__Log("testing sleutel: "+ params.sleutel);
var oCrypto = new ActiveXObject("SLNKDWF.Crypto");
var sig = oCrypto.hex_hmac_sha1(params.sleutel, hmacArr[0] + ":" + str);
var should_hmac = oCrypto.hex2base64(sig, false, true); // no padding, urlsafe
oCrypto = null;
if (hmacArr[1] != should_hmac)
{
__Log("str: " + str);
__Log("hmac: " + hmac);
__Log("HMAC[1]: " + hmacArr[1]);
__Log("SHOULD: " + should_hmac);
if (params.relaxed)
{
__Log("(relaxed==true, will try hmac again with user_key==-1)");
return false;
}
else
INTERNAL_ERROR_HMAC_TAMPERING;
}
return true;
}
}
var protectQS =
{
// Bescherm de url tegen tampering door een hmac achteraan toe te voegen
// Te controleren aan de ontvangende kant met protectQS.verify()
// PAS OP: protectQS.wsc bevat voor Facmgt nog (even) hetzelfde algoritme
create: function(url, params)
{
params = params || {};
var splitter = url.split("?");
var pad = splitter[0];
var qs = splitter.length>1?splitter[1]:"x=x";
var padsplitter = pad.split("/");
var file = padsplitter[padsplitter.length-1]; // laatste component
// Let op dat protectQS.wsc hetzelfde doet voor Facmgt
var data = (params.no_user_key?"":(user_key + ":")) + file.toUpperCase() + "?" + qs;
var hmacced = protectHMAC.create(data, params);
return pad + "?" + qs + "&hmac="+Server.URLencode(hmacced);
},
// params: expire: in minuten. Default 720, een heel kritische functie kan zichzelf scherper beschermen
// allowparams []: bijv. 'outputmode'. Deze worden er voor de HMAC berekening uitgestript
// relaxed: doe niet al te moeilijk over errors (maar wel false)
verify: function (params)
{
params = params || {};
if (params.relaxed && Request.QueryString("hmac").Count == 0)
return false;
// vanuit API2 geven we checkqs en checkpath mee omdat die door IIS Rewrite
// te veel veranderd zijn
var checkurl = params.checkqs || String(Request.QueryString);
if (params.allowparams)
{
var i;
for (i in params.allowparams)
{
var param = params.allowparams[i];
if (Request.QueryString(param).Count > 0)
{ // die rekenen we niet mee in de HMAC
checkurl = checkurl.replace(param + "=" + Request.QueryString(param) + "&", "");
checkurl = checkurl.replace("&" + param + "=" + escape(Request.QueryString(param)), "");
}
}
}
var hmac = getQParam("hmac");
var hmacArr = hmac.split(":");
var indexHmac = String(checkurl).indexOf("&hmac=");
if (checkurl.substring(indexHmac+1).indexOf("&") >=0)
{
if (params.relaxed)
return false;
else
{
__DoLog("HMAC url extension not allowed: {0}".format(checkurl), "#ff0000");
shared.internal_error("HMAC url extension not allowed"); // Net iets minder erg dan een AiAi
}
}
var qs = checkurl.substring(0,indexHmac);
var pad = params.checkpath || String(Request.ServerVariables("SCRIPT_NAME"));
var padsplitter = pad.split("/");
var file = padsplitter[padsplitter.length-1]; // laatste component
// Let op dat create dezelfde data hasht
var data = (params.no_user_key?"":(user_key + ":")) + file.toUpperCase() + "?" +qs;
//__Log("testing hmacdata: " + data);
//__Log("testing sleutel: "+ params.sleutel);
if (params.allow_anonymous)
params.relaxed = true;
var is_ok = protectHMAC.verify(data, getQParam("hmac"), params); // klapt er uit bij hmac-tampering en relaxed==false
if (!is_ok && params.allow_anonymous)
{ // Testen met user_key == -1
var data = "-1" + ":" + file.toUpperCase() + "?" +qs;
params.relaxed = false; // Nu moet hij echt kloppen
protectHMAC.verify(data, getQParam("hmac"), params);
}
return is_ok;
}
}
// http://www.owasp.org/index.php/Session_Fixation_Protection
function setASPFIXATION()
{
var FACSESSIONID = shared.random(32); // genereer grote random string.
var ASPFIXATION = Session("customerId") + FACSESSIONID;
Response.Cookies("ASPFIXATION") = ASPFIXATION; // deze controleren we weer in default.inc
Response.Cookies("ASPFIXATION").Path = rooturl + "/"; // anders niet met ServerXMLHttp
if (S("auto_https") & 2)
Response.Cookies("ASPFIXATION").Secure = true;
Session("RVT_TOKEN") = shared.random(32) + "_" + toISODateTimeString(new Date());
Session("ASPFIXATION") = ASPFIXATION; // deze controleren we weer in default.inc
Session("FACSESSIONID") = FACSESSIONID;
}
var protectRequest =
{
theToken: function () { return Session("RVT_TOKEN") }, // Session RVT_TOKEN wordt gebruikt als anti Cross-Site Request Forgery (CSRF)
theVar: "RVT_token",
inputToken: function () // Maak een hidden inputveld met token
{
%>
<input name="<%=protectRequest.theVar%>" id="<%=(protectRequest.theVar + "_" + (new Date()).getTime())%>" type="hidden" value="<%=safe.htmlattr(protectRequest.theToken())%>">
<%
},
// Van dataToken is ook een clientside variant in iface.js
dataToken: function (dataName) // Voeg aan een data hash een input token toe
{ %>
<%=dataName%>.<%=protectRequest.theVar%> = "<%=safe.jsstring(protectRequest.theToken())%>";
<%
},
validateToken: function (externtoken)
{ // De token van het hidden inputveld valideren met de token van de cookie.
// Voorkeur gaat uit naar het gebruik van getFParam(), maar in Multipart/form-data zijn deze niet beschikbaar.
// De form-parameters worden in upload.inc alsnog uitgelezen, zodat het token aan deze functie meegegeven kan worden.
try // API's hebben vaak inputXML.load(Request); gedaan en dan werkt getFParam niet meer
{
var verificationToken = (externtoken ? externtoken : getFParam(protectRequest.theVar, ""));
}
catch (e)
{ // API's die buildInsert of buildUpdate doen moeten daar vaak { noValidateToken: true } bij doen
__DoLog("INTERNAL_ERROR_TOKEN_VALIDATIE", "#FFFF00");
INTERNAL_ERROR_TOKEN_VALIDATIE;
};
var cookieToken = protectRequest.theToken()||""; // is leeg bij self_register.asp als we nog niet zijn ingelogd.
if (verificationToken != cookieToken)
{ // Is deze functie vanuit een post aangeroepen? Dan afhandeling door post functie af laten handelen.
var message = L("lcl_authentication_error") + "\n" + toISODateTimeString(new Date());
message += "\n(" + verificationToken.substring(verificationToken.length-19) + "==>" + cookieToken.substring(cookieToken.length-19) + ")";
if (typeof DOCTYPE_Disable != "undefined" && DOCTYPE_Disable == 1)
{
var result = {message: message };
Response.Write(JSON.stringify(result));
Response.End;
}
else
{
abort_with_warning(message);
}
}
}
}
var cache = {
whenTrue: function _whenTrue(b)
{
if (b)
{
var eTag = '"' + user.lang() + "_" + S("cache_changecounter") + "_" + Session("ASPFIXATION") + '"'; // Hoogstens zo lang je ingelogd bent
Response.AddHeader("ETag", eTag);
Response.AddHeader("Last-Modified", new Date().toGMTString());
Response.CacheControl = "private";
if (Request.ServerVariables("HTTP_IF_NONE_MATCH") == eTag)
{ // We hebben een match!
var tm = "";
if (Request.ServerVariables("HTTP_IF_MODIFIED_SINCE").Count)
tm = " (" + toISODateTimeString(new Date(Request.ServerVariables("HTTP_IF_MODIFIED_SINCE")), true) + ")";
__Log("Geslaagde caching" + tm + ": we geven status 304 terug en stoppen.");
Response.Clear();
Response.Status = "304 Not modified";
Response.End;
}
}
},
whenNoRecords: function _whenNorecords(sql)
{
var oRs = Oracle.Execute(sql);
this.whenTrue(oRs.Eof);
oRs.Close();
}
}
// Datum functies
Date.prototype.toSQL = function toSQL(withTime, withSeconds)
{
var year = this.getFullYear();
if (year < 1000 || year > 9999)
shared.internal_error("Invalid year " + this.toLocaleString()); // Net iets minder erg dan ORA-01830
var str = padout(this.getDate()) + "-" + padout(this.getMonth() + 1) + "-" + padout(this.getFullYear())
var dateformat = "DD-MM-YYYY";
if (withTime)
{
str += " " + padout(this.getHours()) + ":" + padout(this.getMinutes());
dateformat += " HH24:MI";
if (withSeconds)
{
str += ":" + padout(this.getSeconds());
dateformat += ":SS";
}
}
return "to_date(" + safe.quoted_sql(str) + ", '" + dateformat + "')";
}
Date.prototype.beginToSQL = function beginToSQL(dateOnly)
{
var theDateStart = new Date(this);
theDateStart = new Date(toUserTimeZone(theDateStart).setHours(0, 0));
return toServerTimeZone(theDateStart).toSQL(!dateOnly);
}
Date.prototype.endToSQL = function endToSQL(dateOnly)
{
var theDateEnd = new Date(this);
theDateEnd = new Date(toUserTimeZone(theDateEnd).setHours(23, 59));
return toServerTimeZone(theDateEnd).toSQL(!dateOnly);
}
Date.prototype.midnight = function midnight()
{
var midn = new Date(this);
midn.setHours(0,0,0,0);
return midn;
}
function inArray(needle, haystack) {
var length = haystack.length;
for(var i = 0; i < length; i++) {
if (haystack[i] == needle) return true;
}
return false;
}
function sharedTrim(str) { return str.replace(/^\s+|\s+$/g,""); }
function sharedIndexOf(needle, haystack) {
if (haystack == null || needle == null)
return -1;
for(var i = 0; i < haystack.length; i++) {
if (haystack[i] == needle) return i;
}
return -1;
}
function sortArray(data_arr, sortcolumn_arr)
{
// EXAMPLE:
// var fruits = [ {fruit:"Banana", qty: 2, color: "yellow"}
// , {fruit:"Orange", qty: 4, color: "orange"}
// , {fruit:"Apple" , qty: 3, color: "green"}
// , {fruit:"Apple" , qty: 5, color: "red"}
// , {fruit:"Mango" , qty: 1, color: "purple"}
// ];
// var sf = sortArray(fruits, ["fruit desc "," color asc"]);
// var sf = sortArray(fruits, ["qty desc"]);
// var sf = sortArray(fruits, ["color"]);
function _compare(sc, so)
{
return function (a,b)
{
var result = ( a[sc] < b[sc] ? -1 : (a[sc] > b[sc] ? 1 : 0) );
return result * so;
}
}
function _get_filters(sortstring)
{
var result = [];
var arr = sortstring.split(" ");
for (var i=0; i<arr.length; i++)
{
if (arr[i] != "")
result.push(arr[i]);
}
if (result.length == 1)
result.push(1); // default ASC
else if (result.length == 2)
result[1] = (result[1].toUpperCase().replace(/\s+/g,"") == "DESC" ? -1 : 1);
return result;
}
if (data_arr && sortcolumn_arr)
{
for (var i=sortcolumn_arr.length-1; i>=0; i--)
{
var sc_arr = _get_filters(sortcolumn_arr[i]);
data_arr.sort(_compare(sc_arr[0],sc_arr[1]));
}
}
return data_arr;
}
// Bepaalt de customerId (en rooturl)
// Na afloop is de globale variabele customerId gezet en opgeslagen in Session("customerId")
function determineCustomerId()
{
var validCustId = /[A-Z0-9]/;
// autodetect rooturl. Al onze pagina's beginnen met /cust of met /appl
var pad = String(Request.ServerVariables("PATH_INFO"));
var lowerpad = pad.toLowerCase();
var i1 = lowerpad.indexOf("/cust/");
if (i1 < 0)
i1 = lowerpad.indexOf("/appl/");
if (i1 < 0)
i1 = lowerpad.indexOf("/default.asp"); // API's
/* global */ rooturl = pad.substr(0, i1);
var trycust = "";
if ( typeof Session("customerId") == "undefined" ) // ASP-Sessie verlopen of nieuw binnen.
{
if (Request.QueryString("api").Count>0)
{
Session.Abandon(); // Voorkom dat een session ontstaat doordat we een API-call doen.
// When the Abandon method is called, the current Session object is queued for deletion
// but is not actually deleted until all of the script commands on the current page have
// been processed. This means that you can access variables stored in the Session object
// on the same page as the call to the Abandon method but not in any subsequent Web pages.
}
// is var customerId al gezet door /default.asp?
if (typeof customerId != 'undefined' && customerId != "XXXX")
trycust = customerId.toUpperCase();
else if (String(Request.Cookies("fcltcust"))) // Remember me knop
trycust = String(Request.Cookies("fcltcust"));
else
{ // URL formaat http://xxxx.5iwork/facilitor5iwork: pak eerste 4 letters
var host = String(Request.ServerVariables("HTTP_HOST"));
trycust = host.substring(0,4).toUpperCase();
var fso = Server.CreateObject("Scripting.FileSystemObject");
if (!fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
{
trycust = host.split(".")[0].toUpperCase(); // Misschien hele prefix (C2930)
if (!fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
trycust = null;
}
}
// TODO: is er maar één cust-folder met een Oracle.udl? Gebruik die
}
// Deze overruled alles:
if (getQParamSafe("fac_id","") != "")
var trycust = getQParamSafe("fac_id").toUpperCase();
if (trycust && validCustId.test(trycust)) // Geen vreemde karakters en er is een udl?
{
var fso = Server.CreateObject("Scripting.FileSystemObject");
if (fso.FileExists(Server.MapPath(rooturl + "/cust/" + trycust + "/Oracle.udl")))
Session("customerId") = trycust;
else
{
Response.write("Invalid customerId: " + trycust);
Response.end;
}
}
/* global */ customerId = Session("customerId");
if (typeof customerId == "undefined")// Ik geef het op.
{
if (String(Request.ServerVariables("HTTP_ACCEPT")).match(/application\/json/) != null)
{
var msg = "Your session has expired.\nPlease restart Facilitor."; // L("xxx") vertrouw ik ook niet meer
Response.Write("FCLTExpired:" + msg); // FCLTExpired wordt zo opgepikt door FcltJquery.js ajaxSetup error handler
Response.End;
}
Response.Redirect(rooturl + "/appl/shared/expired.asp");
}
if (!validCustId.test(customerId)) // paranoia
{
INTERNAL_ERROR_BAD_CUSTOMERID;
}
}
function getFileOwner(fullpath)
{
try {
var oAbout = new ActiveXObject("SLNKDWF.About");
if (oAbout.VersionString >= "4,21")
var owner = oAbout.FileOwner(fullpath);
else
var owner = "*unknown*";
}
catch (e)
{
var owner = "*unknown*\n" + e.description;
}
return owner;
}
function getUserContext()
{
try {
var oAbout = new ActiveXObject("SLNKDWF.About");
return oAbout.UserContext;
}
catch (e)
{
return "*unknown*\n" + e.description;
}
}
function getCustXsl(prefix)
{
prefix = prefix || "";
return custpath + "/xsl/" + prefix + customerId + ".xsl";
}
function getCustCss(prefix)
{
prefix = prefix || "";
var fso = Server.CreateObject("Scripting.FileSystemObject");
var cssFile = custpath + "/" + prefix + customerId + ".css";
if (!fso.FileExists(Server.MapPath(cssFile)))
cssFile = custpath + "/" + prefix + "cust.css";
return cssFile;
}
// Er is een onvoorziene fout opgetreden
// Dat loggen we in de reguliere logfile en vervolgens forceren we met een throw die we
// niet catchen dat er een http-500 error optreedt die we dan weer afvangen in 500_error.asp
// TODO: afhankelijk van content-type hier al een JSON opleveren in plaats van
// dat via 500_error te doen?
function _AiAi(txt)
{
if (typeof theLogger != "undefined") // Bijvoorbeeld met http://logc.lokalhost/trunk/appl/fac/fac_report.asp?outputmode=1&mode=yvf...
__DoLog("AiAi: " + txt, '#f00');
Session("last_caller") = __callerTekst(_AiAi.caller); // worden door 500-error.asp opgepikt
Session("last_aiai") = txt;
if (typeof THIS_FILE == "string")
Session("THIS_FILE") = THIS_FILE;
throw(txt);
}
// Merk op dat we een beetje browser capabilities en device capabilities
// op één hoop gooien. Goed genoeg vooralsnog
device =
{ // lower 8 bits
isSupported: 0x0001,
isDesktop : 0x0002,
isTouch : 0x0004,
isMobile : 0x0008,
// next 8 bits
canPrint : 0x0100, // Show print buttons
canExcel : 0x0200, // Show Excel buttons
canUpload : 0x0400, // Can upload files
canDownload: 0x0800, // Can download files
// more
supportsPlaceholder: 0x1000, // Support placeholder attribute of input
_devicebits: 0xff01, // Default desktop, alle capabilities
init: function ()
{
if (typeof Session("devicebits") != "undefined")
this._devicebits = Session("devicebits")
else
Session("devicebits") = this._devicebits;
},
test: function (bits)
{
return ( (this._devicebits & bits) == bits);
},
testAll: function (bits)
{
return test(bits);
},
testAny: function (bits)
{
return ( (this._devicebits & bits) != 0);
},
set: function (bits, newval)
{
if (newval || typeof newval == "undefined")
this._devicebits = this._devicebits | bits;
else // reset
this._devicebits = this._devicebits & (~bits);
Session("devicebits") = this._devicebits;
},
isapp: function ()
{
return Session("aut_client_key") > 0;
}
}
myJSON =
{
internal_parsedate: function (key, value)
{
var a;
if (typeof value === 'string') {
a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
if (a) {
return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
}
}
return value;
},
// myJSON.parse doet hetzelfde als JSON.parse maar herkent automatisch datum variabelen
parse: function _parse(text)
{
return JSON.parse(text, myJSON.internal_parsedate);
}
}
HTTP =
{ // params: type, data, headers, APIKEY (voor API2)
getJSON: function _getJSON(url, params) // Serverside variant van jQuery $.getJSON
{
params = params || {};
if (!params.type)
params.type = params.data?"POST":"GET"; // Met data default POST, zonder data default GET
var http_request = Server.CreateObject("WinHTTP.WinHTTPRequest.5.1");
var vraag = JSON.stringify(params.data, null);
__Log("HTTP url: " + url);
if (vraag)
__Log("data: " + vraag);
http_request.open(params.type, url, false); // Synchroon
// Het volgende lijkt weinig effect te hebben, post-body is nog steeds utf-8?
// in api.inc/RequestJSON verwachten we dan ook maar utf-8 dus netto werkt het goed?
http_request.setRequestHeader("Content-Type", "application/json; charset=windows-1252");
if (params.APIKEY)
http_request.setRequestHeader("X-FACILITOR-API-Key", params.APIKEY);
for ( var i in params.headers )
{
http_request.setRequestHeader(i, params.headers[ i ]);
}
// Het mag niet te lang duren!
var lResolve = 5 * 1000;
var lConnect = 5 * 1000;
var lSend = 15 * 1000;
var lReceive = 15 * 1000;
http_request.setTimeouts(lResolve, lConnect, lSend, lReceive);
var errtxt = "";
var errnum = 0;
try
{
http_request.send(vraag);
}
catch (e)
{
errtxt = e.description;
errnum = e.number;
}
if (!errtxt && http_request.status != 200)
{
// Hier HTML lijkt me misplaatst
errtxt = "HTTP status " + http_request.status
+ ": " + http_request.responseText;
}
if (errtxt)
{
//__DoLog(" url: " + url, "#FF0000");
//__DoLog(" data: " + vraag);
if (errnum == -2147012894) // "The operation timed out", dan is http_request niet te benaderen
__DoLog(" http_request {0} mislukt: {1}".format(url, errtxt), "#FF0000");
else if (http_request.status == 404)
__Log(" http_request status = 404 {0}".format(url));
else if (http_request.status == 401)
__DoLog(" http_request status = 401 {0}".format(url));
else
__DoLog(" http_request {0} mislukt: {1}".format(url, errtxt), "#FF0000");
}
else
{
__Log(http_request.ResponseText);
try
{
var result = myJSON.parse(http_request.ResponseText)
}
catch (e)
{
__DoLog("Parse error: " + e.message);
__DoLog(http_request.ResponseText);
result = { success: false, message: e.message };
}
return result;
}
},
urlzelf: function ()
{
return HTTP.urlzelfnoroot() + rooturl;
},
urlzelfnoroot: function ()
{
var proto = (Request.ServerVariables("SERVER_PORT") == "443")? "https" : "http";
var sitenoroot = proto + "://" + Request.ServerVariables("SERVER_NAME");
return sitenoroot;
}
}
// Alleen nog maar ipv4
// http://stackoverflow.com/a/503238/569090
IP =
{
isIPv4: function(IPaddress)
{
return String(IPaddress).indexOf(".") > -1;
},
isIPv6: function(IPaddress)
{
return String(IPaddress).indexOf(":") > -1;
},
IPnumber: function(IPaddress) {
var ip = IPaddress.match(/^(\d+)\.(\d+)\.(\d+)\.(\d+)$/);
if(ip) {
return (+ip[1]<<24) + (+ip[2]<<16) + (+ip[3]<<8) + (+ip[4]);
}
// else ... ?
__DoLog("Invalid IPAddress: " + IPaddress);
INTERNAL_ERROR_INVALID_IP;
},
IPmask: function (maskSize) {
return -1<<(32-maskSize)
},
inSubnet: function(ip, subnet)
{
var long_ip = IP.IPnumber(ip);
var bits = 32;
if (subnet.indexOf("/") > 0)
{
bits = parseInt(subnet.split("/")[1], 10);
subnet = subnet.split("/")[0];
}
if (bits == 0) // extra omdat IPmask(0) een overflow geeft
return true;
var mask = IP.IPmask(bits);
var long_subnet = IP.IPnumber(subnet);
return (long_ip & mask) == (long_subnet & mask);
},
// subnets gescheiden door komma's
inAnySubnet: function(ip, subnets)
{
if (!subnets)
INTERNAL_ERROR_NOSUBNETS; // 'k weet niet of default veilig of onveilig gewenst is
var arr = String(subnets).split(",");
for (var i = 0; i < arr.length; i++)
{
if (IP.inSubnet(ip, arr[i]))
return true;
}
return false;
}
}
%>