<%@language="javascript"%>
<% /*
    $Revision$
    $Id$

    File:           shared/500_error.asp
    Description:    In IIS in te stellen als custom 500-error pagina

    Note:           Je zit hier in de context van het *originele* script
                    Request.ServerVariables("PATH_INFO") is het originele bestand

                    Het is heel verleidelijk common.inc te includen. Stel echter dat de database niet bereikbaar is?
                    Dan klapt m_connections.inc er weer opnieuw uit en hebben we nog niets bereikt.
                    Daarom gebruiken we ook geen lcl's in dit bestand maar hardcoded teksten.
                    Logger.inc durf ik nog net aan voor het gemak

                    Er wordt geprobeerd te detecteren dat het om een API aanroep gaat. Dan wordt geen
                    html opgeleverd maar een JSON met de foutmelding.
*/ %>
<!-- #include file="../Shared/logger.inc" -->
<!-- #include file="../Shared/shared.inc" -->
<!-- #include file="../Shared/json2.js" -->
<!-- #include file="../api2/api2_rest.inc" -->
<%
try { Response.Clear; } catch (e) {};

if (Request.QueryString("check500").Count > 0)
{
    Response.Write("OK500"); // voor fac_verify.asp
    Response.End;
}

if (Session("THIS_FILE"))
{
    THIS_FILE = Session("THIS_FILE");
    Session.Contents.Remove("THIS_FILE");
}

var lcls_NL = {
   lcl_AiAi: "Aiai!",
   lcl_timeout: "Het opvragen van de pagina duurde te lang.",
   lcl_solution: "Een mogelijke oplossing kan zijn om uw zoekfilter aan te passen zodat minder resultaten worden opgeleverd.",
   lcl_toobig: "De opgevraagde pagina is te groot.",
   lcl_error: "Er is iets fout gegaan, maar dat ligt waarschijnlijk niet aan u.",
   lcl_registered: "Deze fout wordt automatisch geregistreerd en onderzocht.",
   lcl_refresh: "U kunt wellicht het beste uw browser verversen en verder gaan met uw werk."
}
var lcls_EN = {
   lcl_AiAi: "Aiai!",
   lcl_timeout: "The requested page timed out.",
   lcl_solution: "A possible solution may be to change your search filter in order to produce less results.",
   lcl_toobig: "The requested page is too big.",
   lcl_error: "Something went wrong but this is most likely not your fault.",
   lcl_registered: "This error is automatically registered and will be investigated.",
   lcl_refresh: "The best course of action may be to refresh your browser and continue your work."

}
var lcls = lcls_NL;
if (Session("user_lang") != "NL")
    lcls = lcls_EN;

function L(p_lcl)
{
    return lcls[p_lcl];
}

// Bij list-pagina's geven we als hint om het zoek-filter scherper in te stellen
function isListPage()
{
    return String(Request.ServerVariables("SCRIPT_NAME")).match(/list/i)
        || String(Request.ServerVariables("SCRIPT_NAME")).match(/res_search_plan/i)
        || String(Request.ServerVariables("SCRIPT_NAME")).match(/fac_report.asp/i)
        || Request.QueryString("mode") == "list";
}

var objASPError = Server.GetLastError;
var proto = (Request.ServerVariables("SERVER_PORT") == "443")? "https" : "http";
var method = String(Request.ServerVariables("REQUEST_METHOD"));
var sitenoroot = proto + "://" + Request.ServerVariables("SERVER_NAME");
// Opgepikt door logger.inc
var hiresTimer = null;
var __LogfileName = LogfileName();
var __LogfileTitle = "AiAi";
var __LogNoClear = true;
var __LogfileClass = "cls_" + Session("customerId") ;

// Waarschijnlijk een jQuery ajax
var format = String(Request.QueryString("format")).toLowerCase();
if (String(Request.ServerVariables("HTTP_ACCEPT")).match(/application\/json/) != null ||
    String(Request.ServerVariables("HTTP_X-Requested-With")) == "XMLHttpRequest" ||
    String(Request.ServerVariables("HTTP_USER_AGENT")).match("WinHttp.WinHttpRequest.5") ||
    Response.ContentType == 'application/json' ||
    (Request.QueryString("api2").Count > 0 && format != "scf")
    )
{
    switch (objASPError.ASPCode)
    {
        case "ASP 0113": // Script timed out
        {
            var msg = L("lcl_timeout");
            if (isListPage())
            {
                msg += "\n" + L("lcl_solution");
            }
            break;
        }
        case "ASP 0251": // Response Buffer Limit Exceeded
        {
            var msg = L("lcl_toobig");
            if (isListPage())
            {
                msg += "\n" + L("lcl_solution");
            }
            break;
        }
        default:
        {
            var msg = "Aiai"
                    + "\n" + L("lcl_error")
                    + "\n" + L("lcl_registered")
                    + "\n" + L("lcl_refresh");
            break;
        }
    }
    msg += "\n\nFacilitor " + toISODateTimeString(new Date())
        + ", " + sitenoroot;

    if (__Logging > 0)
    {
        msg += "\n(Zie " + LogfileName() + ")";
    }
    if (Application("otap_environment") == "O" || __Logging > 0)
    {
        msg += "\n----------------\n(gaat niet naar klanten:)";
        if (Session("last_aiai"))
            msg += "\n" + Server.HTMLEncode(Session("last_aiai")) + "\n";
        if (objASPError.Description)
            msg += "\n" + objASPError.Description + "\n" + objASPError.File + "(" + objASPError.Line + ")";
    }

    if (Request.QueryString("api2").Count > 0)
    {
        var data = { error: { code: 500,
                              message: msg
                            }
                   };
        if (Application("otap_environment") == "O" || __Logging > 0)
        {
            data.error.internal = ASPErrorJson();
            if (Session("last_aiai"))
                data.error.internal.Aiai = Session("last_aiai");
            if (Session("last_caller"))
                data.error.internal.Caller = Session("last_caller");
        }

        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));
        }
    }
    else
    {
        try { Response.ContentType = "text/plain"; } catch (e) {/* Response.Buffering niet aan? */};
        Response.Write("FCLTFriendly:" + msg); // FCLTFriendly wordt zo opgepikt door FcltJquery.js ajaxSetup error handler
    }
    LogErrorToFile();
    Response.End;
};

// Als we hier komen gaan we HTML opleveren. Daar contenttype ook op proberen aan te passen?
try { Response.ContentType = "text/html"; } catch (e) {/* Response.Buffering niet aan? */};

// Breek heel grof uit eventuele geneste HTML zodat onze tekst duidelijk in beeld komt
Response.Write("</script></table></table></option></select></form>");

// Dit gaat naar de eindgebruiker:

// styling vrij hard omdat we niet op css kunnen rekenen
%>
<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=windows-1252">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
    <style>
        body {
            font-family:Arial,Helvetica;
            font-size: 90%!important;
        }
        div.aiai {
            text-align: left;
            border: 3px solid #FF6F6F;
            border-radius: 10px;
            padding: 20px 20px 40px 20px;
            width: 450px;
            font-size:1em;
            font-weight: normal;
            color: black;
            background-color: #fff0f0;
        }
        table tbody tr td {
            font-family: Courier;
            font-size:12px;
            padding: 2px;
        }
        table.source {
            background-color: #f8f8f8;
            border: 1px solid #ddd;
            border-collapse: collapse;
            padding: 5px;
        }
        td.linenr {
            background-color: white;
            border-right: 1px solid #ddd;
            text-align: right;
            width: 40px;
            padding-right: 4px;
        }
        pre { margin: 0px;
              background-color: #f8f8f8;
        }
        .important {
            font-weight: bold;
            background-color: #fee;
        }
        .klein {
            font-size: 8px;
        }
    </style>
</head>
<body>
<div class='aiai'>
<h1 style='color:red'><%=L("lcl_AiAi")%></h1>
<%
switch (objASPError.ASPCode)
{
    case "ASP 0113": // Script timed out
    {
        Response.Write(L("lcl_timeout"));
        if (isListPage())
        {
            Response.Write("<br><br>" + L("lcl_solution"));
        }
        break;
    }
    case "ASP 0251": // Response Buffer Limit Exceeded
    {
        Response.Write(L("lcl_toobig"));
        if (isListPage())
        {
            Response.Write("<br><br>" + L("lcl_solution"));
        }
        break;
    }
    default:
    {
        Response.Write(L("lcl_error"));
        Response.Write("\n<br><br><span style='font-size:0.8em'>" + L("lcl_registered"));
        Response.Write("\n<br>" + L("lcl_refresh") + "</span>");
        break;
    }
}
Response.Write("\n<br><br><span style='font-size:0.8em;'>Facilitor "+toISODateTimeString(new Date())+"</span>");
Response.Write("\n<br><span style='font-size:0.8em;'>" + sitenoroot + "</span>");

Response.Write("</div></body></html>");

if (Application("otap_environment") == "O" || __Logging > 0)
{
  Response.Write("\n<p>De rest is niet zichtbaar voor klanten.<br>");
  Response.Write("\n<span class='klein'>\\cust\\custenv.wsc heeft Overrule.APPLICATION(\"otap_environment\", \"O\"); of logging staat aan</span></p>");

  Response.Write("\n<hr><p>Zie <a href='" + rooturl + "/appl/fac/fac_StreamFile.asp?logger=3' target='_blank'>AiAi logfile</a> "
                 + " of de <a href='" + rooturl + "/appl/fac/fac_StreamFile.asp?logger=0' target='_blank'>gewone logfile </a>"
                 + "voor meer details of klik <a href='javascript:location.reload()'><button onclick='this.innerText=\"Please wait...\";'>Refresh</button></a> om het opnieuw te proberen.</p>");

  var pad = String(Request.ServerVariables("PATH_TRANSLATED"));
  var params = String(Request.ServerVariables("QUERY_STRING"));
  if (params!="")
  {
      pad += "?" + params;
  }
  var y = String(Request.ServerVariables("APPL_PHYSICAL_PATH")); // Zoveel gaan we er af strippen
  pad = pad.substring(y.length);
  var extra = "<tr><td>Customer:</td><td>" + Session("customerId") + (rooturl.length>1?'@'+rooturl.substr(1):"") + "</td></tr>";

  // Lees de UDL tekstueel uit. We zitten al in de problemen dus we hebben geen m_connections.inc
  var ForReading = 1;
  var tsUnicode = -1;

  var fso = new ActiveXObject("Scripting.FileSystemObject");
  var udl = Server.MapPath(rooturl + "/cust/" + Session("customerId") + "/Oracle.udl");
  try
  {
      var f = fso.OpenTextFile(udl, ForReading, true, tsUnicode);
      var s = f.ReadLine();
      s = f.ReadLine();
      s = f.ReadLine(); //3e regel is interessant
      // Provider=OraOLEDB.Oracle.1;Password=xxxxx;Persist Security Info=True;User ID=hcas;Data Source=fclt
      var sa = s.split(";");
      var data = [];
      var uid = "";
      var tns = "";
      for (var i = 0; i < sa.length; i++)
      {
          var itma = sa[i].split("=");
          if (itma.length == 2)
          {
              if (itma[0] == 'User ID')
                uid =  itma[1];
              if (itma[0] == 'Data Source')
                tns =  itma[1];
          }
      }
      f.Close();
  }
  catch (e)
  {
    uid = "Not found";
    tns = udl;
  }
  extra += "<tr><td>Database:</td><td>" + uid + "@" + tns + "</td></tr>";

  var ttl = "?" + params.replace(/\%2C/g, ",").split("&").join("\n&");
  extra += "<tr><td>Url:</td><td title='" + Server.HTMLEncode(ttl) + "'>" + Server.HTMLEncode(method + " " + pad) + "</td></tr>";
  Response.Write(ASPErrorText(extra));

  if (objASPError.Line > 0)
      Response.Write("\n<br>" + ShowSourcecode(-8, +4));
}
LogErrorToFile(); // verwijdert ook last_sql

Response.End;

function ASPErrorText(extra)
{
    var err = "<table class='error'>";
    err += (extra||"");

    var props = ["Category", "ASPCode", "ASPDescription", "Description", "File", "Line", "Column", "Source", "Number"];
    for (v in props)
    {
      if (objASPError[props[v]])
      {
        var myVal = objASPError[props[v]];
        var safeprop = Server.HTMLEncode(myVal).replace(/\n/g,"<br/>");
        if (props[v] == 'Description' && !Session("last_aiai"))
        {
            safeprop = "<span class='important'>" + safeprop + "</span>";
            if (myVal.match(/ORA\-/) && Session("badschema"))
                safeprop += "<br><span class='important'>Perhaps bad schema: " + Session("badschema") + "</span>";
            if (myVal.match(/0x80040e4b/)) // The system cannot find message text for message number 0x80040e4b in the message file for OraOLEDB.
                safeprop += "<br><span xclass='important'>Hint: 0x80040e4b is usually an indication of an extreme date value like 21-11-0024<br>"
                         +      "Oracle can handle this fine but ADODB/OLEDB not</span>";
        }
        if (props[v] == 'Column' && myVal == -1)
            continue; // niet interessant
        if (props[v] == 'Number' && !isNaN(myVal))
        {
            if (myVal < 0)
                myVal = 0xFFFFFFFF + myVal + 1;
            safeprop += " (0x" + myVal.toString(16) + ")"
        }
        err += "\n<tr><td style='vertical-align:top'>"+props[v]+":</td><td>" + safeprop + "</td></tr>";
      }
    }
    if (Session("last_aiai")) // vanuit shared.inc/function _AiAi
    {
        err += "\n<tr><td style='vertical-align:top'>AiAi:</td><td style='max-width: 800px;' class='important'>" + Server.HTMLEncode(Session("last_aiai")).replace(/\n/g, '<br>') + "</td></tr>";
    }
    if (Session("last_caller")) // vanuit m_connections.inc
    {   // last_caller wordt in logger.inc ook altijd al safe beschouwd, Server.HTMLEncode niet nodig
        err += "\n<tr><td style='vertical-align:top'>Call stack:</td><td style='max-width: 800px;'>" + Session("last_caller") + "</td></tr>";
    }
    if (Session("last_sql")) // vanuit m_connections.inc
    {
        err += "\n<tr><td style='vertical-align:top'>Last SQL:</td><td style='max-width: 800px;' class='important'>" + Server.HTMLEncode(Session("last_sql")) + "</td></tr>";
    }

    var hmac = String(Request.QueryString("hmac"));
    if (hmac)
    {
        var tm = parseInt(hmac.split(":")[0]);
        if (!isNaN(tm))
            err += "\n<tr><td style='vertical-align:top'>HMAC issued:</td><td>" + toISODateTimeString(new Date(tm*1000)) + "</td></tr>";
    }

    err += "</table>";
    return err;
}

function ASPErrorJson()
{
    var err = {};
    var props = ["Category", "ASPCode", "ASPDescription", "Description", "File", "Line", "Column", "Source", "Number"];
    for (v in props)
    {
      if (objASPError[props[v]])
      {
        err[props[v]] = objASPError[props[v]];
      }
    }
    return err;
}

function LogErrorToFile()
{
    var pathinfo = String(Request.ServerVariables("PATH_INFO"));
    if (Session("customerId"))
        __SafeDoLog("CustomerId: " + Session("customerId"), "#f00");
    else
    {
        __DoLog("Strange, Session(\"customerId\") is not set.\nPerhaps this is a direct request to: " + sitenoroot + pathinfo, "#f88");
        __DoLog("Probably a &fac_id= parameter set the customerId. That's ok.");
    }
    if (method != "POST" && pathinfo.indexOf("_save") > -1)
    {
        __DoLog("Strange, " + method + " of a save-script, I expected a POST", "#f88");
    }

    __SafeDoLog(ASPErrorText());

    __Logstd(Session("last_aiai") || objASPError.Description, "E");

    Session.Contents.Remove("last_sql"); // Nu weg, anders worden ze bij Sessions ook nog getoond
    Session.Contents.Remove("last_caller");
    Session.Contents.Remove("last_aiai");
    if (Request.ServerVariables("HTTP_REFERER").Count)
        __DoLog("Referer: " + Request.ServerVariables("HTTP_REFERER"));
    if (Session("page_start"))
    {
        var now = new Date();
        var start = new Date(Session("page_start"));
        var duration = Math.round((now.getTime() - start.getTime()) / 100) / 10;
        if (duration >= 10)
            __SafeDoLog("Page started at " + toISODateTimeString(start) + " which is " + duration + " seconds ago");
    }
    if (!Response.IsClientConnected)
    {
        __SafeDoLog("Response.IsClientConnected is false, enduser probably already closed the page and did not see this AiAi");
    }
    if (objASPError.Line > 0)
        __SafeDoLog(ShowSourcecode(-8, +4));

    if (Request.QueryString.Count>0) // Hele URL is al wel gelogd maar dit is leesbaarder
    {
        __SafeDoLog(__DumpCollection(Request.QueryString, { title: "Request.QueryString" }));
    }
    try
    {
         var contenttype = String(Request.ServerVariables("HTTP_CONTENT_TYPE"));
         var contentmime = String(Request.ServerVariables("HTTP_CONTENT_TYPE")).split(";")[0];
         if (method == "POST" || Request.TotalBytes > 0)
            __DoLog("Request body " + Request.TotalBytes + " bytes\nContent-type: " + contenttype);
         if (Request.Form.Count >0)
            __DoLogForm();
    }
    catch(e)
    {
        if (contentmime == 'application/x-www-form-urlencoded')
            __SafeDoLog(Server.HTMLEncode(e.description) + "<br>Loggen form mislukt terwijl contentmime == 'application/x-www-form-urlencoded'")
    }
    __SafeDoLog(__DumpCollection(Session.Contents, { title: "Session", exclude: /ASPFIXATION|FACSESSIONID/i }));
    __SafeDoLog("IP: " + Request.ServerVariables("REMOTE_ADDR") + "<br>Useragent: " + Server.HTMLEncode(Request.ServerVariables("HTTP_USER_AGENT")));
}

var rooturl;
function LogfileName()
{
// 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);

    // Zoek de TempFolder, de enige folder met 'gegarandeerd' schrijfrechten
    var fso = Server.CreateObject("Scripting.FileSystemObject");
    var sPath = Server.MapPath("./");

    while (fso.FolderExists(sPath) && !fso.FolderExists(sPath + "/temp"))
    {
        sPath = fso.GetParentFolderName(sPath);
    }
    if (!fso.FolderExists(sPath + "/temp") || !fso.FolderExists(sPath + "/appl") || !fso.FolderExists(sPath + "/cust"))
        return null; // Het moet wel de TEMP folder zijn naast APPL, niet toevallig eentje in de root

    // Naam van de AiAi folder bepalen. Kijk daartoe of er al een folder is van de vorm /temp/_AiAi_error_xxxxx
    var f = fso.GetFolder(sPath + "/temp/");
    var fname = "_AiAi_error";

    var nowtxt = toISODateString(new Date());
    var folder = sPath + "/temp/" + fname;
    if (!fso.FolderExists(folder))
        fso.CreateFolder(folder);
    return folder + "/log_" + nowtxt + ".html";
}

function ShowSourcecode(minregel, plusregel)
{
    if (!objASPError.File)
    {
        return "<span style='background-color:magenta'><p>Vreemd genoeg geen objASPError.File?</span>";
    }
    var fso = Server.CreateObject("Scripting.FileSystemObject");
    var fpath = objASPError.File; // meestal is dit een relatief pad maar ik heb meegemaakt
    if (fpath.indexOf(":") == -1) // (lokaal W10, na een rename van een bestand?) dat het een volledig pad was
        var fpath = Server.MapPath(objASPError.File);
    var myF = fso.GetFile(fpath);
    var ts = new Date(myF.DateLastModified);
    var result = "Source: "+objASPError.File + " (" + toISODateTimeString(ts) + ")<br>";
    var myFile = fso.OpenTextFile(fpath);
    var ll =0;
    while (!myFile.AtEndOfStream && ll < objASPError.Line + minregel)
    {
        ll ++;
        myFile.SkipLine();
    }
    result += "<table class='source'>";
    while (!myFile.AtEndOfStream && ll < objASPError.Line + plusregel)
    {
        ll++;
        var stl = "";
        var txt = myFile.ReadLine();
        if (ll==objASPError.Line)
        {
            stl = "style='background-color:#e0fafa'";
            if (objASPError.Column > 0)
            {
                txt = Server.HTMLEncode(txt.substr(0, objASPError.Column))
                    + "<span style='background-color:#f88;'>"
                    +       Server.HTMLEncode(txt.substr(objASPError.Column, 1))
                    + "</span>"
                    + Server.HTMLEncode(txt.substr(objASPError.Column + 1));
            }
            else
                txt = Server.HTMLEncode(txt);
        }
        else
            txt = Server.HTMLEncode(txt);
        result += "\n<tr><td class='linenr'>" + ll + "</td><td class='source'><pre "+stl+">" + txt + "</pre></td></tr>";
    }
    myFile.Close()
    result += "</table>";
    return result;
}

%>
<% ASPPAGE_END(); %>
