<% /*
    $Revision$
    $Id$

    File:               FlexFiles.inc
    Description:
    Parameters:
    Context:
    Note:               pModule, pKey en pSubpath worden genormaliseerd
                        tot simpele/veilige  padnamen
*/

var fso = Server.CreateObject("Scripting.FileSystemObject"); // Die hebben we hier *zo* vaak nodig.

function iso8601Date(jsDate)
{
  var str = padout(jsDate.getFullYear())
          + padout(jsDate.getMonth() + 1)
          + padout(jsDate.getDate())
          + "T"
          + padout(jsDate.getHours())
          + padout(jsDate.getMinutes())
          + padout(jsDate.getSeconds());
  return str;
}

function renameIphoneIpadFiles(pfilename, pcounter)
{
  if (pfilename.match(/image.jpg/i) || pfilename.match(/image.jpeg/i) || pfilename.match(/image.png/i) ||
      pfilename.match(/afbeelding.jpg/i) || pfilename.match(/afbeelding.jpeg/i) || pfilename.match(/afbeelding.png/i))
  { // Bij gelijktijdig uploaden van bestanden is een timestamp op seconde niet toereikend.
    // We doen de teller er ook nog maar bij.
    var fileName = pfilename.split(".");
    var ext = fileName[fileName.length - 1];
    fileName = fileName.slice(0, -1).join(".");
    var newfilename = fileName + "_{0}{1}.{2}".format(iso8601Date(new Date), (pcounter > 0? "_" + pcounter : ""), ext);
    __Log("-->Ios: " + newfilename);
    return newfilename;
  }
  else
    return null;
}


function trackBijlagen(pModule, pKey, params, result, action)
{
  if (pKey > -1 && params.trackcode && (params.kenmerktype == "E" || params.kenmerktype == "F" || params.kenmerktype == "M"))
  {
    if (pModule == "BEZ") { // Voor afpraken heb ik de afspraak key nodig i.p.v. de bezoekerskey om de kenmerk omschrijving te bepalen.
      var sql = "SELECT bez_afspraak_key" +
                "  FROM bez_bezoekers" +
                " WHERE bez_bezoekers_key = " + pKey;
      var oRs = Oracle.Execute(sql);
      var afspr_key = oRs("bez_afspraak_key").Value;
      oRs.close();
      pKey = String(afspr_key);
    }

    var ptxt;
    var j;
    if (action == "upload")
    {
      for (j = 0; j < result.safefilename.length; j++)
      {
        if (params.kenmerksysteem & 4)
          ptxt = L("lcl_shared_attachment_add").format(params.kenmerkoms, L("lcl_confidential_mask"));
        else
          ptxt = L("lcl_shared_attachment_add").format(params.kenmerkoms, result.safefilename[j]);
        shared.trackaction(params.trackcode, pKey, ptxt);
      }
    }
    else if (action == "delete")
    {
      if (params.kenmerksysteem & 4)
        ptxt = L("lcl_shared_attachment_delete").format(params.kenmerkoms, L("lcl_confidential_mask"));
      else
        ptxt = L("lcl_shared_attachment_delete").format(params.kenmerkoms, safe.filename(pDoDelete));
      shared.trackaction(params.trackcode, pKey, ptxt);
    }

    if (pModule == "MLD" && params.niveau == "M" && action=="upload")
    {
      var mld_key = pKey;
      var mfe = mld.func_enabled_melding (mld_key);
      if (mfe.haveOnlyFErights)
      {
        var mld_info = mld.mld_melding_info(mld_key);
        // Bij het toevoegen van een bijlage (alleen door de FrontEnd) bij notities onder water de flags/status/notitificatie doen
        // alsof er een notitie was getikt door die Frontend.
        var result = mld_note_save(mld_key,
                                   ptxt, // Text van de notitie.
                                   { note_key:           -1,    // Als een nieuwe notitie.
                                     note_parent_key:    -1,
                                     has_zichtbaarFE:    false,
                                     zichtFE:            true,
                                     notifyFE:           false,
                                     notifyFEchild:      false,
                                     notifyExt:          false,
                                     action2FE:          false,
                                     has_action2BO:      mld_info.actiecode != 1,
                                     action2BO:          mld_info.actiecode != 1, // Als FE + actie niet bij BO, dan actie naar BO. Idem als bij notities.
                                     has_notifyBO:       false,
                                     notifyBO:           false,
                                     fac_note_group_key: null,
                                     ismailnote:         0,
                                     bijlage:            true   // Het betreft een bijlage i.p.v. een notitie. Dan alleen de flags/status/notitificatie doen.
                                   });
      }
    }
  }
}

function bepaalNiveau(pModule, pNiveau)
{
  if (pModule == "MLD")
  {
    if ("MO".indexOf(pNiveau) >=0)
        return pNiveau;
    else
        INTERNAL_ERROR_PNIVEAU;
  }
  if (pModule == "PRS")
  {
    if ("ABCP".indexOf(pNiveau) >=0)
        return pNiveau;
    else
        INTERNAL_ERROR_PNIVEAU;
  }

  // return pModule.substr(0,1) zou waarschijnlijk ook voldoen
  switch (pModule)
  {
    case "ALG": pNiveau = "A";
                break;
    case "BES":
    case "BEZ": pNiveau = "B";
                break;
    case "CNT": pNiveau = "C";
                break;
    case "FIN": pNiveau = "F";
                break;
    case "INS": pNiveau = (pNiveau ? pNiveau : "I"); // S voor sleutel (en toekomst: C voor controle/inspectie)
                break;
    case "MRK": pNiveau = "M";
                break;
    case "RES": pNiveau = "R";
                break;
    case "FAQ": pNiveau = "F";
                break;
  }
  return pNiveau;
}

function kenmerkwaardetabel_info(pModule, pNiveau)
{
    // zie ook FAC_PACFLEX.src
    var kmw = {module: pModule};
    switch (pModule)
    {
        case "ALG": kmw.tabel  = "alg_onrgoedkenmerk";
                    kmw.refkey = "alg_onrgoed_key";
                    break;
        case "BES": if (pNiveau == "I")
                    {   kmw.module = "BES";
                        kmw.tabel  = "bes_kenmerkbesteli";
                        kmw.refkey = "bes_bestelling_item_key";
                    }
                    if (pNiveau == "B")
                    {   kmw.module = "BES";
                        kmw.tabel   = "bes_kenmerkbestell";
                        kmw.ref_key = "bes_bestelling_key";
                    }
                    break;
        case "BEZ": kmw.tabel  = "bez_kenmerkwaarde";
                    kmw.refkey = "bez_bezoekers_key";
                    break;
        case "CNT": kmw.tabel  = "cnt_kenmerkcontract";
                    kmw.refkey = "cnt_contract_key";
                    break;
        case "FAQ": kmw.tabel  = "faq_kenmerkwaarde";
                    kmw.refkey = "fac_faq_key";
                    break;
        case "FIN": if (pNiveau == "R")
                    {   kmw.module = "FIN";
                        kmw.tabel  = "fin_kenmerkfactregel";
                        kmw.refkey = "fin_factuurregel_key";
                    }
                    if (pNiveau == "F")
                    {   kmw.module = "FIN";
                        kmw.tabel  = "fin_kenmerkfactuur";
                        kmw.refkey = "fin_factuur_key";
                    }
                    break;
        case "INS": kmw.tabel  = "ins_kenmerkdeel";
                    kmw.refkey = "ins_deel_key";
                    break;
        case "MLD": if (pNiveau == "M")
                    {   kmw.module = "MLD";
                        kmw.tabel  = "mld_kenmerkmelding";
                        kmw.refkey = "mld_melding_key";
                    }
                    if (pNiveau == "O")
                    {   kmw.module = "OPD";
                        kmw.tabel  = "mld_kenmerkopdr";
                        kmw.refkey = "mld_opdr_key";
                    }
                    break;
        case "PRS": kmw.tabel  = "prs_kenmerklink";
                    kmw.refkey = "prs_link_key";
                    break;
        case "RES": kmw.module = "RES";
                    kmw.tabel  = "res_kenmerkwaarde";
                    kmw.refkey = "res_rsv_ruimte_key";
                    //kmw.tabel  = "res_kenmerkartikel";
                    //kmw.refkey = "res_rsv_artikel_key";
                    break;
    }

    kmw.kenmerkkey = pModule   + "_kenmerk_key";
    kmw.waarde     = kmw.tabel + "_waarde";
    kmw.verwijder  = kmw.tabel + "_verwijder";

    // Uitzondering:
    if (pModule == "RES")
        kmw.waarde = "res_kenmerkreservering_waarde";
    return kmw;
}

var cache_bepaalKenmerkGegevens = []; // vanuit API2 mogelijk voor heel veel records aangeroepen
function bepaalKenmerkGegevens(pModule, pKenmerkkey)
{
  if (pKenmerkkey == null)
    return {kenmerk_omschrijving: null, kenmerk_type: null};

  var cache_code = pModule + "_" + pKenmerkkey;
  if (cache_code in cache_bepaalKenmerkGegevens)
    return cache_bepaalKenmerkGegevens[cache_code];

  var table;
  var srttable;
  switch (pModule)
  {
    case "ALG":   table = "alg_kenmerk";
                  break;
    case "BES":   table = "bes_kenmerk";
                  srttable = "bes_srtkenmerk";
                  break;
    case "BEZ":   table = "bez_kenmerk";
                  break;
    case "CNT":   table = "cnt_kenmerk";
                  srttable = "cnt_srtkenmerk";
                  break;
    case "FIN":   table = "fin_kenmerk";
                  break;
    case "INS":   table = "ins_kenmerk";
                  srttable = "ins_srtkenmerk";
                  break;
    case "MLD":   table = "mld_kenmerk";
                  srttable = "mld_srtkenmerk";
                  break;
    case "PRS":   table = "prs_kenmerk";
                  break;
    case "RES":   table = "res_kenmerk";
                  srttable = "res_srtkenmerk";
                  break;
    case "FAQ":   table = "faq_kenmerk";
                  break;
  }

  cache_bepaalKenmerkGegevens[cache_code] = {};
  var sql = "SELECT " + lcl.xsql((srttable? "sk." + srttable : "k." + table) + "_omschrijving", (srttable? "sk." + srttable : "k." + table) + "_key") + " kenmerk_omschrijving"
          + "     ,  " + (srttable? srttable : table) + "_kenmerktype kenmerk_type"
          + "     ,  " + (srttable? srttable : table) + "_systeem kenmerk_systeem"
          + "     ,  " + table + "_regexp kenmerk_regexp"
          + "  FROM " + table + " k"
          + (srttable
            ? "   , " + srttable + " sk"
            : "")
          + " WHERE k." + table + "_key = " + pKenmerkkey
          + (srttable
            ? "   AND k." + srttable + "_key = sk." + srttable + "_key"
            : "")
  var oRs = Oracle.Execute(sql);
  if (!oRs.eof)
  {
    var kenmerk_omschrijving = oRs("kenmerk_omschrijving").Value;
    var kenmerk_type = oRs("kenmerk_type").Value;
    var kenmerk_systeem = oRs("kenmerk_systeem").Value;
    var kenmerk_regexp = oRs("kenmerk_regexp").Value;
    cache_bepaalKenmerkGegevens[cache_code] = {kenmerk_omschrijving: kenmerk_omschrijving, kenmerk_type: kenmerk_type, kenmerk_systeem: kenmerk_systeem, kenmerk_regexp: kenmerk_regexp}
  }
  oRs.close();

  return cache_bepaalKenmerkGegevens[cache_code];
}

function subfolderNew(pNiveau, pId)
{
  return pNiveau + "__NEW__" + pId;
}

function subfolderKey(pNiveau, pKey)
{
  var keyStr = "0000000" + pKey;
  var subfolder = pNiveau + keyStr.substr(keyStr.length-7,4) + "___/" + pNiveau + pKey;
  return subfolder;
}

// Codering: M=MLD:K=12345:S=587:N=M:R=R400x400,F=AMSG0-01-A047.JPG
function flexProps2(flexcode)
{
    var Module, Key, Subpath, Niveau, getparams;
    var getparams = { getFiles: true };

    var codes = flexcode.split(":");
    for (var i = 0; i < codes.length; i++)
    {
        var code = codes[i].substr(0,1);
        var data = codes[i].substr(2);
        switch (codes[i].substr(0,1))
        {
            case "M": Module = data;
                      break;
            case "K": Key = data; // Ik zou hier willen testen met parseInt maar bijvoorbeeld bij graphics is de Key een dwf-bestandsnaam
                      if (!Key)
                        shared.internal_error("Bad key in '{0}'".format(Server.HTMLEncode(flexcode)));
                      break;
            case "S": Subpath = data; // Doorgaans kenmerk key
                      break;
            case "N": Niveau = data;
                      break;
            case "F": getparams.getFile = data;
                      break;
            case "R": getparams.resizeCode = data;
                      break;
        }
    }

    var params = flexProps(Module, Key, Subpath, Niveau, getparams);
    return params;
}
function flexProps(pModule, pKey, pSubpath, pNiveau, params)
{
  params = params || {};
  var result = { directlink: false,
                 files: [],
                 autfunctionapiread: 'WEB_PRSSYS', // default streng, logfiles zetten we later zelfs op FACTAB
                 autfunctionapiwrite: 'WEB_PRSSYS',
                 autfunctionapibrowse: 'WEB_PRSSYS'
  };
  var pKenmerk_key = (isNaN(parseInt(pSubpath)) ? -1 : parseInt(pSubpath));
  switch (pModule)
  {
      case "FGII": // Facilitor Graphics
          result.pickfile = true;
      case "FGII_M": // Facilitor Graphics - Hele map zien
          result.AttachRootPath = S("flexfilespath") + "/cad/concept/";
          result.AttachPath = result.AttachRootPath;
          result.multi = true;
          result.searchfile = true;
          result.extFilter = "dwf";
          break;
      case "FGIIV": // Vluchtplannen
          result.AttachRootPath = S("flexfilespath") + "/cad/vlucht/";
          result.AttachPath = result.AttachRootPath + "V" + pKey + "/";
          result.multi = true;
          result.extFilter = "dwf";
          break;
      case "FGIIS": // Facilitor Graphics symbolen
          result.AttachRootPath = S("flexfilespath") + "/cad/symbols/";
          result.AttachPath = result.AttachRootPath;
          result.extFilter = "dwf";
          result.linkImmediate = {
            "table"     : "ins_srtdeel",
            "key_col"   : "ins_srtdeel_key",
            "link_col"  : "ins_srtdeel_acadsymbol"
          }
          break;
      case "FGIIP":
          result.AttachRootPath = S("flexfilespath") + "/cad/prj/";
          result.AttachPath = result.AttachRootPath + pKey + "/";
          result.multi = true;
          result.extFilter = "dwf";
          break;
      case "FGIIA": // Facilitor Graphics Actueel (alleen download)
          result.AttachRootPath = S("flexfilespath") + "/cad/";
          result.AttachPath = result.AttachRootPath;
          result.searchfile = true;
          result.multi = true;
          result.extFilter = "dwf";
          settings.overrule_setting("flexFilesOrdering", 0);
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "BESPH":
          // Bestanden zijn te vinden op prs_bedrijf.prs_bedrijf_image_loc of ...cust/xxxx/photos/bes/[disc_key]/
          // Wij kunnen alleen bestanden naar ...cust/xxxx/photos/bes/[disc_key]/ uploaden.
          result.AttachRootPath = Server.MapPath(S("bes_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("bes_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("bes_photo_size");
          result.directlink = true;
          result.linkImmediate = "bes_srtdeel";
          break;
      case "INSPHS": // ins_srtdeel (Objectsoort)
          // Bestanden zijn te vinden op ...cust/x/photos/ins
          result.AttachRootPath = Server.MapPath(S("ins_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("ins_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("ins_photo_size");
          result.directlink = true;
          result.linkImmediate = "ins_srtdeel";
          break;
      case "BESD": // bes_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("besd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("besd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("bes_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
      case "BGTD": // bgt_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("bgtd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("bgtd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("bgt_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
      case "INSD": // ins_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("insd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("insd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("ins_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
      case "CNTD": // cnt_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("cntd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("cntd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("cnt_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
      case "RESD": // ins_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("resd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("resd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("res_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
       case "MLDS": // Stdmelding symbolen
          result.AttachRootPath = Server.MapPath(S("mlds_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("mlds_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("mld_photo_size");
          result.directlink = true;
          result.linkImmediate = "mld_stdmelding";
          break;
       case "MLDG": // Meldinggroep symbolen
          result.AttachRootPath = Server.MapPath(S("mldg_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("mldg_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("mld_photo_size");
          result.directlink = true;
          result.linkImmediate = "mld_stdmeldinggroep";
          break;
      case "MLDD": // mld_discipline symbolen
          result.AttachRootPath = Server.MapPath(S("mldd_image_path"));
          result.RelativePath = S("mldd_image_path");
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("mld_photo_size");
          result.directlink = true;
          result.linkImmediate = "discipline";
          break;
      case "MLDSD": // mld_srtdiscipline symbolen
          result.AttachRootPath = Server.MapPath(S("mldsd_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("mldsd_image_path");
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("mld_photo_size");
          result.directlink = true;
          result.linkImmediate = "ins_srtdiscipline";
          break;
      case "ALG":
      case "BES":
      case "BEZ":
      case "CNT":
      case "FIN":
      case "INS":
      case "MLD":
      case "PRS":
      case "RES":
      case "FAQ":
          // Bestanden zijn nu te vinden on ...cust/x/flexfiles/[module]/[subfolder]/[key]/[kenmerk_key]
          result.fac_bijlagen = true; // registreren in fac_bijlagen
          result.AttachRootPath = (pKey > 0? S("flexFilesPath") : shared.tempFolder());
          result.AttachSubPath = pModule + "/";
          result.AttachSubPath += (pKey > 0? subfolderKey(bepaalNiveau(pModule, pNiveau), pKey)
                                           : subfolderNew(bepaalNiveau(pModule, pNiveau), user_key + "_" + (params.tmpfolder||getQParam("tmpfolder",""))));
          result.AttachSubPath += "/" + pSubpath;
          result.AttachPath = result.AttachRootPath + "/" + result.AttachSubPath + "/";

	      // de volgende twee wil ik liever met de kenmerk-key opzoeken in de database
          // maar dat is even te veel werk hier. De url is toch hmac-protected
          result.extFilter = getQParam("extFilter", S("flexExtensionFilter"));
          result.encrypt = getQParamInt("encrypt", 0) == 1;
          result.regexp = getQParam("pregexp", ""); //P800x600 cropt/resized naar 800x600
          if (pModule == "ALG" && params)
          {
            result.trackcode = pModule + params.alglevel + "UP";
            var kenmerk_geg = bepaalKenmerkGegevens(pModule, pSubpath);
            result.kenmerkoms = kenmerk_geg.kenmerk_omschrijving;
            result.kenmerktype = kenmerk_geg.kenmerk_type;
            result.kenmerksysteem = kenmerk_geg.kenmerk_systeem;
          }
          else if (pModule != "FAQ")
          {
            if (pModule == "MLD" && pNiveau == "O")
              result.trackcode = "ORD" + "UPD";
            else if (pModule == "INS" && pNiveau == "I")
              result.trackcode = "INS" + "CUP";
            else
              result.trackcode = pModule + "UPD";
            var kenmerk_geg = bepaalKenmerkGegevens(pModule, pSubpath);
            result.kenmerkoms = kenmerk_geg.kenmerk_omschrijving;
            result.kenmerktype = kenmerk_geg.kenmerk_type;
            result.kenmerksysteem = kenmerk_geg.kenmerk_systeem;
            result.regexp = (result.regexp ? result.regexp : kenmerk_geg.kenmerk_regexp);
          }
          break;
      case "NEWS": // Het plaatje horende bij het nieuwsbericht
          result.forcesingle = true; // Verwijder eventuele anderen
          result.regexp = S("msg_photo_size");
      case "FAQA": // BB-plaatjes binnen antwoord van kennisbankitem.
      case "FAQB": // BB-plaatjes binnen nadere info van kennisbankitem.
      case "MES": // BB-plaatjes binnen 'Bericht versturen'
      case "MSG": // BB-plaatjes binnen het nieuwsbericht
          result.AttachSubPath = pModule + "/";
          result.extFilter = S("imgAllowedExt");
      case "ORDN":
      case "MLDN":
          var folder_prefix = pModule.slice(0, 1);
      case "ALGN":
      case "CNTN":
      case "FINN":
      case "INSN":
          result.fac_bijlagen = true; // registreren in fac_bijlagen
          result.AttachRootPath = (pKey > 0 ? S("flexFilesPath") : shared.tempFolder());
          result.AttachSubPath = result.AttachSubPath || (pModule.slice(0, -1) + "/NOTE/");
          result.AttachSubPath += (typeof folder_prefix !== "undefined" ? folder_prefix : "")
                                + (pKey > 0 ? String(pKey) : "__NEW__" + String(user_key));
          result.AttachPath = result.AttachRootPath + "/" + result.AttachSubPath + "/";
          break;
      case "ALGPHL":
      case "ALGPHG":
      case "ALGPHT":
          // Bestanden zijn te vinden op ...cust/x/photos
          if (pModule == "ALGPHL") {
            result.AttachSubPath = "locatie";
            result.linkImmediate = "alg_locatie";
          } else if (pModule == "ALGPHG") {
            result.AttachSubPath = "gebouw";
            result.linkImmediate = "alg_gebouw";
          } else if (pModule == "ALGPHT") {
            result.AttachSubPath = "terrein";
            result.linkImmediate = "alg_terreinsector";
          }
          result.AttachRootPath = Server.MapPath(S("alg_image_path")) + "/" + result.AttachSubPath;
          result.RelativePath = S("alg_image_path") + result.AttachSubPath + "/";
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("alg_photo_size");
          result.directlink = true;
          break;
      case "RESPHR": /* Reserveerbare Ruimte */
      case "RESPHO": /* Opstelling */
      case "RESPHA": /* Verbruiksartikel */
      case "RESPHD": /* Reserveerbaar Object */
          // Bestanden zijn te vinden op ...cust/x/photos
          // Raar; res_ruimte en res_ruimte_opstelling delen dezelfde map, en dat is ook nog eens de hoofdmap; /photos/
          if (pModule == "RESPHR") {
            result.linkImmediate = "res_ruimte";
          } else if (pModule == "RESPHO") {
            result.linkImmediate = {
                "table"   : "res_ruimte_opstelling",
                "key_col" : "res_ruimte_opstel_key",
                "link_col": "res_ruimte_opstel_image"
            }
          } else if (pModule == "RESPHA") {
            result.AttachSubPath = "artikel";
            result.linkImmediate = "res_artikel";
          } else if (pModule == "RESPHD") {
            result.AttachSubPath = "deel";
            result.linkImmediate = "res_deel";
          }
          result.AttachRootPath = Server.MapPath(S("res_image_path")) + (result.AttachSubPath ? "/" + result.AttachSubPath: "");
          result.RelativePath = S("res_image_path") + (result.AttachSubPath ? result.AttachSubPath + "/" : "");
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("res_photo_size");
          result.directlink = true;
          break;
      case "MRK":
          result.AttachRootPath = Server.MapPath(S("mrk_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.AttachPath += (pKey > 0? subfolderKey("M", pKey)
                                        : subfolderNew("M", Session.SessionId));
          result.AttachPath += "/1/";
          result.RelativePath = S("mrk_image_path") + subfolderKey("M", pKey) + "/1/";
          result.multi = false; // vooralsnog maar eentje
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("mrk_photo_size");
          result.directlink = true;
          break;
      case "SML":
          result.AttachRootPath = Server.MapPath(S("prs_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.AttachPath += subfolderKey("P", pKey);
          result.AttachPath += "/SML/";
          result.RelativePath = S("prs_image_path") + subfolderKey("P", pKey) + "/SML/";
          result.multi = false; // vooralsnog maar eentje
          result.forcesingle = true; // verwijder eventuele anderen
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("sml_photo_size"); // "r200x150", Resized naar binnen 200x150 (zonder crop, met behoud aspect ratio)
          result.directlink = true;
          break;
      case "INSPHD":
          // Deze vervangt de flexoplossing.
          // Bestanden zijn te vinden op ...cust/x/photos
          result.AttachRootPath = Server.MapPath(S("ins_image_path"));
          result.AttachRootPath += '/deel';
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("ins_image_path") + "deel/";
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("ins_photo_size"); // "r200x150", Resized naar binnen 200x150 (zonder crop, met behoud aspect ratio)
          result.directlink = true;
          result.linkImmediate = "ins_deel";
          break;
      case "MENU":
          result.AttachRootPath = Server.MapPath(S("menu_image_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("menu_image_path");
          result.extFilter = S("flexExtensionFilter"); // was "jpg|png"; maar tegenwoordig ook andere bestanden
          result.regexp = S("menu_photo_size");
          result.directlink = true;
          result.linkImmediate = "fac_menu";
          break;
      case "MENUURL": // Menu bestanden die worden gebruikt als url.
          result.AttachRootPath = Server.MapPath(S("menu_image_url_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("menu_image_url_path");
          result.extFilter = S("flexExtensionFilter"); // Alle bestanden mogen worden geupload. Niet alleen pdf.
          result.directlink = true;
          result.linkImmediate = {
            "table"     : "fac_menu",
            "key_col"   : "fac_menu_key",
            "link_col"  : "fac_menu_alturl"
          }
          break;
      case "BDRADR":
          result.AttachRootPath = Server.MapPath(S("bdradrfiles_path"));
          result.AttachPath = result.AttachRootPath + "/";
          result.RelativePath = S("bdradrfiles_path") + "/";
          result.extFilter = S("flexExtensionFilter"); // Mag in principe alles zijn
          result.directlink = true;
          result.pickfile = true;
          result.multi = true;
          break;
      case "CUSTXSL":
          result.AttachRootPath = Server.MapPath(custpath + "/xsl");
          result.AttachPath = result.AttachRootPath + "/";
          result.multi = true;
          result.extFilter = "xsl";
          result.keephistory = true;
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk xsl toestaan
          settings.overrule_setting("flexFilesOrdering", 0);
          break;
      case "CUSTIMP":
          result.AttachRootPath = Server.MapPath(custpath + "/import");
          result.AttachPath = result.AttachRootPath + "/";
          result.multi = true;
          result.extFilter = "log";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk log toestaan
          settings.overrule_setting("flexFilesOrdering", 0);
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "CUSTEXP":
          result.AttachRootPath = Server.MapPath(custpath + "/export");
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "log";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk log toestaan
          settings.overrule_setting("flexFilesOrdering", 0);
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "CUSTTASKS":
          result.AttachRootPath = Server.MapPath(custpath + "/tasks"); // Volgens mij is hier sinds 2019.2 niets meer te vinden
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "log";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk log toestaan
          settings.overrule_setting("flexFilesOrdering", 0);
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "CUSTEXCH":
          result.AttachRootPath = shared.tempFolder() + "/exchange";
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "log";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk log toestaan
          settings.overrule_setting("flexFilesOrdering", 0);
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "CUSTTEMP":
          result.AttachRootPath = shared.tempFolder();
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "xml|json|txt|html|log";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan, altijd fijn
          result.searchfile = true;
          result.maxfiles = 5;
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "CUSTTEMPPUO":
          result.AttachRootPath = shared.tempFolder() + "/putorders";
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "xml|json|txt|html";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan. Ik weet dat putorders toevallig sorteerbare namen aanmaakt
          result.searchfile = true;
          result.maxfiles = 5;
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "AIAI":
          result.AttachRootPath = Server.MapPath(rooturl + "/temp/_AiAi_error");
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "html";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan.
          result.searchfile = true;
          result.nodigest = true; // overbodig voor logfiles
          result.maxfiles = 5;
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "SMTP": // Veronderstel hMailserver op default locatie
          result.AttachRootPath = "C:\\Program Files (x86)\\hMailServer\\Logs";
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "log|zip";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan.
          result.searchfile = true;
          result.nodigest = true; // overbodig voor logfiles
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "SHIB": // Veronderstel Shibboleth op default locatie
          result.AttachRootPath = "C:\\opt\\shibboleth-sp\\var\\log\\shibboleth";
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = "log|[0-9]*";
          settings.overrule_setting("flexAllowedExt", result.extFilter); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan.
          result.searchfile = true;
          result.nodigest = true; // shibd.log wil nog wel eens locked zijn
          result.autfunctionapiread = 'WEB_FACTAB';
          result.autfunctionapiwrite = 'WEB_FACTAB';
          break;
      case "EXPORTS": // EXPORTS/FIN
          var export_app_key = params.imp_exp_key;
          if (export_app_key > 0)
          {
            sql = "SELECT * FROM fac_export_app WHERE fac_export_app_key = " + export_app_key;
          }
          else
          {
            var export_code = params.iecode;
            sql = "SELECT * FROM fac_export_app WHERE fac_export_app_code = " + safe.quoted_sql_upper(export_code);
          }

          var oRs = Oracle.Execute(sql);
          if (oRs.Eof)
              shared.simpel_page("Undefined export " + (export_app_key || export_code));

          result.autfunctionapiread = oRs("fac_functie_key").Value;
          result.autfunctionapibrowse = oRs("fac_export_app_browse_f_key").Value;
          //result.autfunctionapiwrite = oRs("fac_functie_key").Value;
          result.AttachRootPath = oRs("fac_export_app_folder").Value;
          if (!result.AttachRootPath)
              shared.simpel_page("No export folder configured");
          if (result.AttachRootPath.substr(1, 1) != ":") // dan relatief
          {
              result.AttachRootPath = Server.MapPath(custpath + "/export/" + result.AttachRootPath);
              result.AttachRootPath = fso.GetAbsolutePathName(result.AttachRootPath); // voor de vele ../export/
          }
          result.AttachPath = result.AttachRootPath + "/";
          var postfix = oRs("fac_export_app_postfix").Value;
          if (postfix && postfix.indexOf(".") > -1)
          {
              result.extFilter = postfix.split(".").pop();
          }
          if ((oRs("fac_export_app_flags").Value||0) & 1)
            result.extFilter = "zip";
          //settings.overrule_setting("flexAllowedExt", oRs("fac_folder_extfilter").Value); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan.
          result.searchfile = true;
          result.maxfiles = 10;
          oRs.Close();
          break;
      case "IMPORTS": // IMPORTS/PRS
          var import_app_key = params.imp_exp_key;
          if (import_app_key > 0)
          {
            sql = "SELECT * FROM fac_import_app WHERE fac_import_app_key = " + import_app_key;
          }
          else
          {
            var import_code = params.iecode;
            sql = "SELECT * FROM fac_import_app WHERE fac_import_app_code = " + safe.quoted_sql_upper(import_code)
          }

          var oRs = Oracle.Execute(sql);
          if (oRs.Eof)
              shared.simpel_page("Undefined import " + (import_app_key || import_code));
          result.autfunctionapiwrite = oRs("fac_functie_key").Value;
          result.autfunctionapiread = oRs("fac_functie_key").Value;
          result.autfunctionapibrowse = oRs("fac_import_app_browse_f_key").Value;
          result.AttachRootPath = oRs("fac_import_app_folder").Value;
          if (!result.AttachRootPath)
              shared.simpel_page("No import folder configured");
          if (result.AttachRootPath && result.AttachRootPath.substr(1, 1) != ":") // dan relatief
          {
              result.AttachRootPath = Server.MapPath(custpath + "/import/" + result.AttachRootPath);
              // result.AttachRootPath = fso.GetAbsolutePathName(result.AttachRootPath); // voor als we ooit .. in padnamen moeten ondersteunen
          }
          result.AttachPath = result.AttachRootPath + "/";
          //result.extFilter = oRs("fac_folder_extfilter").Value;
          //settings.overrule_setting("flexAllowedExt", oRs("fac_folder_extfilter").Value); // tijdelijk meer toestaan
          settings.overrule_setting("flexFilesOrdering", 1); // nieuwste bovenaan.
          result.searchfile = true;
          result.maxfiles = 10;
          oRs.Close();
          break;
      case "STYLE":
          result.AttachRootPath = Server.MapPath(S("style_image_path"));
          result.RelativePath = S("style_image_path");
          result.AttachPath = result.AttachRootPath + "/";
          result.extFilter = S("imgAllowedExt");
          result.regexp = S("menu_photo_size");
          result.directlink = true;
          result.pickfile = true;
          result.multi = true;
          break;
      default:
            _AiAi("INTERNAL_ERROR, invalid module {0}".format(pModule));
  }

  if (result.AttachRootPath.indexOf("..") > -1 || // paranoia mode, should never happen
    result.AttachPath.indexOf("..") > -1)
  {
    __DoLog("Bad attach path with '..'\nAttachRootPath: {0}\nAttachPath: {1}".format(result.AttachRootPath, result.AttachPath), '#F00');
    INTERNAL_ERROR_BAD_ATTACHPATH;
  }

  if (params.resizeCode)
    result.resizeCode = params.resizeCode;
  result.AttachRootPath = result.AttachRootPath.replace("..", "_");
  result.AttachPath = result.AttachPath.replace("..", "_");

  if (typeof result.linkImmediate === "string") { // Alleen tabelnaam mag ook, dan gaan we uit van _key en _image column-namen
    if (result.linkImmediate === "discipline") {
      result.linkImmediate = {
        "table"   : "ins_tab_discipline",
        "key_col" : "ins_discipline_key",
        "link_col": "ins_discipline_image"
      }
    } else {
      result.linkImmediate = {
        "table"   : result.linkImmediate,
        "key_col" : result.linkImmediate + "_key",
        "link_col": result.linkImmediate + "_image"
      }
    }
  }

  if (result.fac_bijlagen && ((pKey > 0) || params.bijlagen_key > 0))
  {
      var v_bijlagen = get_bijlagen(pModule, pKey, pKenmerk_key, params.bijlagen_key, pNiveau, params.kenmerk_geldig);
      for (b = 0; b < v_bijlagen.length; b++)
      {
        var filedata = oneFileInfo(v_bijlagen[b], result, pModule, pKey, pSubpath, pNiveau, params);
        result.files.push(filedata);
      }
  }
  else
  {
      var oCrypto = new ActiveXObject("SLNKDWF.Crypto");

      if (params.showall) { // 'Alle bijlagen'
        result.pickfile = false;
        result.multi = true;
      } else if (!params.getFile && params.getFiles && "linkImmediate" in result && !result.multi) {
          params.getFiles = false; // Ik wil er eigenlijk altijd maar 1
          if (pKey > 0) {
              params.getFile = getLinkedFilename(pKey, result);
          } else if (typeof pKey === "string") {
              params.getFile = pKey;
          }

          if (params.getFile && pModule.indexOf("FGII") === 0) { // Deze worden mogelijk zonder extensie opgeslagen in de DB
              params.getFile = params.getFile.replace(/(\.dwf)?$/, ".dwf");
          }
      }

      if (params.getFile)
      {
        if (fso.FileExists(result.AttachPath + params.getFile))
        {
            var fsoFile = fso.GetFile(result.AttachPath + params.getFile);
            var extension = fsoFile.Name.split(".").pop().toLowerCase();
            var ffile = { key:      -1
                        , name:     fsoFile.Name
                        , mimetype: S("flex_mimetypes")[extension]||null
                        , diskname: ""
                        , date:     new Date(fsoFile.DateLastModified)
                        , size:     fsoFile.Size
                        , digest:   (result.nodigest||params.nodigest)?null:oCrypto.hex_sha1_file(result.AttachPath + fsoFile.Name)
                        }
            var filedata = oneFileInfo(ffile, result, pModule, pKey, pSubpath, pNiveau, params);
            result.files.push(filedata);
        }
      }
      else if (params.getFiles)
      {
        if (fso.FolderExists(result.AttachPath))
        {
            __Log("Scanning {0} for files".format(result.AttachPath));
            var f = fso.GetFolder(result.AttachPath);
            var fc = new Enumerator(f.files);

            var totalfiles = 0;
            for (; !fc.atEnd(); fc.moveNext())
            {
                totalfiles ++;
                var fsoFile = fc.item();
                if (params.filter && !(new RegExp(params.filter, "i").test(fsoFile.Name))) {
                    continue;
                }

                if (result.extFilter && !(new RegExp(".({0})$".format(result.extFilter), "i").test(fsoFile.Name))) {
                    continue;
                }
                var extension = fsoFile.Name.split(".").pop().toLowerCase();
                var ffile = { key:      -1
                            , name:     fsoFile.Name
                            , mimetype: S("flex_mimetypes")[extension]
                            , diskname: ""
                            , date:     new Date(fsoFile.DateLastModified)
                            , size:     fsoFile.Size
                            , digest:   (result.nodigest||params.nodigest)?null:oCrypto.hex_sha1_file(result.AttachPath + fsoFile.Name)
                            }

                if (result.keephistory && ffile.name.match(/_20[0-9]{6}_[0-9]{6}\./))
                {
                    ffile.ishistory = true;
                }
                var filedata = oneFileInfo(ffile, result, pModule, pKey, pSubpath, pNiveau, params);
                result.files.push(filedata);
            }
            __Log("Found {0}/{1} files".format(result.files.length, totalfiles));
        }
        else
            __Log("Folder does not exist (yet): " + result.AttachPath);

      }
  }

  result.isAllowedName = function _isAllowedName(FileName)
  {
      if (result.extFilter)
      {
        var regFilter = result.extFilter;
        regFilter = regFilter.replace(/( |,|;)/g,"|"); // Altijd | karakter
        regFilter = ".*\\." + "(" + regFilter + ")$"; // er moet een punt voor en extensie is aan het einde
      }
      else
        regFilter = ".*";
      return (new RegExp(S("flexAllowedExt"), "ig").test(FileName) &&
              new RegExp(regFilter, "ig").test(FileName));
  }

  return result;
}

function oneFileInfo(pFileData, pResult, pModule, pKey, pSubpath, pNiveau, params)
{
    var filedata = pFileData;
    var fName = filedata.name;
    var fSubPath = (filedata.diskpath ? filedata.diskpath : pResult.AttachsubPath);
    var fAttachPath = pResult.AttachRootPath + "/" + (fSubPath ? fSubPath + "/" : "");
    if (params.getFileEncoded == "base64" || params.getFileEncoded == "hex")
    {
        if (fso.FileExists(fAttachPath + fName))
        {
            // Verleidelijk om new ActiveXObject("SLNKDWF.Crypto").base64 in te zetten
            // Die kan echter alleen text-input aan, niet binary data
            var oStream = Server.CreateObject("ADODB.Stream");
            oStream.Open;
            oStream.Type = 1; // adTypeBinary
            oStream.LoadFromFile(safe.UNC(fAttachPath + fName));

            var oXML = new ActiveXObject("Msxml2.DOMDocument.6.0");
            var oNode = oXML.createElement("encodeddata");
            oNode.dataType = params.getFileEncoded == "base64"?"bin.base64":"bin.hex"; // Zeer snelle oplossing
            oNode.nodeTypedValue = oStream.read(oStream.Size);
            filedata.data = oNode.text.replace(/\n/g, ""); // Ik wil de newlines er niet in hebben
            oStream.Close();
        }
        else
            __Log("Bestand niet aangetroffen in: " + fAttachPath + fName);
    }

    // IIS 7+ geeft 404.11 op een plus-teken in een url. Historisch hebben we daar
    // vele bestanden mee en die hernoemen we hier on-the-fly. Er kan nu een
    // afwijking ontstaan bij 'F' kenmerken. die in de database zijn opgeslagen
    // maar dat nemen we voor lief. In de praktijk is dat nooit probleem.
    // Als we *niet* hernoemen hebben we grotere problemen
    if (fName.toLowerCase() != safe.filename(fName).toLowerCase())
    {
        filedata.name = safe.filename(fName);
        __DoLog("Auto renaming {0} to safer {1}".format(fAttachPath + fName, fAttachPath + filedata.name), "#FFFF00");
        if (!fso.fileExists(fAttachPath + filedata.name))
        {
            fso.MoveFile(fAttachPath + fName, fAttachPath + filedata.name);
            var sql_u = "UPDATE fac_bijlagen"
                      + "   SET fac_bijlagen_filename = " + safe.quoted_sql(filedata.name)
                      + " WHERE fac_bijlagen_key = " + filedata.key;
            Oracle.Execute(sql_u);
        }
    }

    if (params.resizeCode)
    {
        var resize_params = { resizecode: params.resizeCode
                            , attachpath: pResult.AttachPath
                            , filename:   filedata.name
                            , safename:   pResult.safefilename
                            , digest:     filedata.digest
                            , isupload:   false
                            };
        var resize_result = resizePicture(resize_params);
        if (resize_result.newsize && (resize_result.newsize > 0))
        {
            filedata.resized = resize_result.file_resized;
            filedata.tempdelete = resize_result.file_tempdelete;
        }
    }

    if (params.tmpfolder)
    {
        filedata.token = params.tmpfolder;
    }
    else if (params.api2name == 'files')
    {
        filedata.deepurl = HTTP.urlzelf() + "/api2/{0}/{1}{2}/{3}".format(
                                        params.api2name,
                                        params.module.toLowerCase(),
                                        (params.module.match(/IMPORTS|EXPORTS/)?"/"+params.iecode:""),
                                        safe.filename(filedata.name) // onze filename is ondertussen dusdanig safe
                                                                     // dat ik het zonder encoding aandurf
                            );
    }
    else if (params.api2name)
    {
        filedata.deepurl = HTTP.urlzelf() + "/api2/{0}/{1}/attachments/{2}/{3}".format(
                                        params.api2name,
                                        pKey,
                                        pSubpath,
                                        safe.filename(filedata.name) // onze filename is ondertussen dusdanig safe
                                                                     // dat ik het zonder encoding aandurf
                            );
    }
    else
    {
      if (pResult.directlink)
      {
        var root = HTTP.urlzelfnoroot() + pResult.RelativePath;
        if (pModule.substr(0, 5) == "ALGPH") {
          root = HTTP.urlzelfnoroot() + S("alg_image_path");
          if (pModule == "ALGPHL")
              root += 'locatie/';
          if (pModule == "ALGPHG")
              root += 'gebouw/';
          if (pModule == "ALGPHT")
              root += 'terrein/';
        } else if (pModule.substr(0, 5) == "RESPH") {
          root = HTTP.urlzelfnoroot() + S("res_image_path");
          if (pModule == "RESPHA")
              root += 'artikel/';
          if (pModule == "RESPHD")
              root += 'deel/';
        }
        filedata.deepurl = root + filedata.name;
      }
      else // Alleen streaming, bestand staat buiten webroot?
      {
        var deepurl = HTTP.urlzelf() + "/appl/shared/BijlagenStream.asp"
                    + "?module=" + pModule;
        if (filedata.key > 0)
        {
            deepurl += "&bijlagen_key=" + filedata.key;
            if (inArray(pModule, ["ORDN", "MLDN"])) { // Eerst maar eens zo
                var sql;
                if (pModule === "ORDN") {
                    sql = "SELECT mld_opdr_key refkey"
                        + "  FROM mld_opdr_note"
                        + " WHERE mld_opdr_note_key = ";
                } else if (pModule === "MLDN") {
                    sql = "SELECT mld_melding_key refkey"
                        + "  FROM mld_melding_note"
                        + " WHERE mld_melding_note_key = ";
                }
                sql += "(SELECT fac_bijlagen_refkey"
                     + "   FROM fac_bijlagen"
                     + "  WHERE fac_bijlagen_key = " + filedata.key + ")";
                var oRs = Oracle.Execute(sql);
                if (!oRs.EoF) {
                    if (pModule === "ORDN") {
                        deepurl += "&opdr_key=";
                    } else if (pModule === "MLDN") {
                        deepurl += "&mld_key=";
                    }
                    deepurl += oRs("refkey").Value;
                }
                oRs.Close();
            }
        }
        else
        {
            deepurl += "&key=" + pKey
                     + (pNiveau ? "&niveau=" + pNiveau : "")
                     + (pSubpath ? "&kenmerk_key=" + pSubpath : "")
                     +  "&filename=" + Server.URLencode(filedata.name)
                     + (filedata.digest ? "&digest=" + Server.URLencode(filedata.digest) : "");
        }
        filedata.deepurl = protectQS.create(deepurl, { cacheablehmac: params.cacheablehmac });
      }
    }
    return filedata;
}

function resizePicture(pic)
{
    // Resize een plaatje eventueel (bij upload)
    var result = {};
    pic.safename = pic.safename || pic.filename;
    __Log("Resizing: " + pic.filename);
    var oIMG = new ActiveXObject("SLNKDWF.ImageConvert");
    var filter = ".*\\.(" + S("imgAllowedExt") + ")$"; //Aangezien dit niet gebeurt in fac_set.src (zoals dat bij flexAllowedExt gebeurt)
    if (new RegExp(filter, "ig").test(pic.filename))
    {
        try
        {
            oIMG.Open(pic.attachpath + pic.filename);
        }
        catch(e)
        {
            __DoLog("Kan plaatje {0} niet laden\n{1}".format(pic.attachpath + pic.filename, e.description));
            // Gewoon negeren
            return result;
        }

        if (pic.resizecode)
        {
            var Format = pic.resizecode.match(/^([RrCc])(\d*)x(\d*)$/i); // R800x600
            if (Format && Format.length == 4)
            {
                var RrCc = Format[1];
                var h0 = h = parseInt(Format[2], 10);
                var w0 = w = parseInt(Format[3], 10);
                if (RrCc == "R" || RrCc == "r") // Dan niet croppen maar aspect ratio behouden
                {
                    if (oIMG.Width * h > w * oIMG.Height)
                        h = parseInt(oIMG.Height / oIMG.Width * w);
                    else
                        w = parseInt(oIMG.Width / oIMG.Height * h);
                }

                if (oIMG.Height < h || oIMG.Width < w) // Zou er iets vergroot gaan worden.
                {
                    if (pic.isupload && (RrCc == "R" || RrCc == "C")) // Dan zijn we streng en eisen we minimale afmeting
                    {
                        result.message = L("lcl_shared_photo_small").format(h0, w0, oIMG.Height, oIMG.Width);
                        DeleteFile(pic.attachpath + pic.safename);
                    }
                    else // Dan maar niet, we vergroten niet.
                    {
                        __Log("Foto is te klein maar we vergroten nooit")
                        h = oIMG.Height;
                        w = oIMG.Width;
                    }
                }

                if (!result.message && (oIMG.Height != h || oIMG.Width != w))
                {
                    try {
                        __Log("Resize/Cropping from w=" + oIMG.Width + " h=" + oIMG.Height + " to w=" + w + " h=" + h);
                        oIMG.Width = w;
                        oIMG.Height = h;
                        var tempfile = shared.tempFolder() + "/img_" + customerId + "_" + pic.digest + "_" + pic.resizecode + "." + fso.GetExtensionName(pic.filename);
                        oIMG.SaveAs(tempfile);
                        result.newsize = getFilesize(tempfile);
                        result.file_resized = tempfile;
                        if (__Logging == 0)
                            result.file_tempdelete = tempfile; // Moet aanroeper opruimen
                    }
                    catch (e)
                    {
                        __DoLog(L("lcl_shared_thumbnail_error") + e.description, "#f00")
                        result.message = L("lcl_shared_thumbnail_error");
                        if (pic.isupload)
                        { // Gewoon opruimen
                            DeleteFile(pic.attachpath + pic.safename);
                        }
                    }
                }
            }
        }
        if (!result.message)
        {
            switch (pic.module)
            {
                case "RESPHD": maxThumbW = 192; maxThumbH = 144; break;
                case "INSPHD": maxThumbW = 192; maxThumbH = 144; break;
                case "SML":    maxThumbW =  80; maxThumbH =  60; break;
                default:       maxThumbW = 100; maxThumbH = 100;
            }
            switch (pic.module)
            {   // Thumbnail altijd voor onderstaanden
                case "RESPHD":
                case "INSPHD":
                case "SML":
                    try
                    {
                        if (oIMG.Width / oIMG.Height > maxThumbW / maxThumbH)
                        {
                            oIMG.Height = oIMG.Height / oIMG.Width * maxThumbW;
                            oIMG.Width = maxThumbW;
                        }
                        else
                        {
                            oIMG.Width = oIMG.Width / oIMG.Height * maxThumbH;
                            oIMG.Height = maxThumbH;
                        }
                        CreateFullPath(pic.attachpath + "thumb/");
                        oIMG.SaveAs(pic.attachpath + "thumb/" + pic.safename);
                    }
                    catch (e)
                    {
                        __DoLog(L("lcl_shared_thumbnail_error") + e.description, "#f00")
                        result.message = L("lcl_shared_thumbnail_error");
                        DeleteFile(pic.attachpath + "thumb/" + pic.safename);
                    }
                    break;
                default: __Log("No thumbnail for module " + pic.module); // Bijv. flexkenmerk foto
            }
        }
    }
    return result;
}

function get_bijlagen(p_module, p_refkey, p_kenmerkkey, p_flexwaarde, pNiveau, pkenmerk_geldig)
{
    var sql = "SELECT DISTINCT"
            + "       b.fac_bijlagen_key"
            + "     , b.fac_bijlagen_refkey"
            + "     , r.fac_bijlagen_key    root_key"
            + "     , r.fac_bijlagen_refkey root_refkey"
            + "     , TRIM(TRANSLATE(SUBSTR(r.fac_bijlagen_disk_directory,5,1), '0123456789', ' ')) fac_bijlagen_niveau"
            + "     , r.fac_bijlagen_kenmerk_key"
            + "     , r.fac_bijlagen_root_key"
            + "     , r.fac_bijlagen_disk_directory"
            + "     , r.fac_bijlagen_disk_filename"
            + "     , b.fac_bijlagen_filename"
            + "     , r.fac_bijlagen_file_size"
            + "     , b.fac_bijlagen_aanmaak"
            + "     , r.fac_bijlagen_digest"
            + "  FROM fac_bijlagen r"
            + "     , fac_bijlagen b"
            + " WHERE r.fac_bijlagen_verwijder IS NULL"
            + "   AND b.fac_bijlagen_verwijder IS NULL"
            + "   AND b.fac_bijlagen_root_key = r.fac_bijlagen_key"
            + "   AND b.fac_bijlagen_module = " + safe.quoted_sql(p_module);

    if (p_flexwaarde) // JGL: volgens mij is dit nooit een bestandsnaam (is ook niet uniek)
    {                 //      sterker nog: ik kan geen codepad vinden waarbij deze parameter daadwerkelijk gezet raakt?
        var v_flexwaarde = parseInt(p_flexwaarde, 10);
        if (isNaN(v_flexwaarde))
        {
            sql += " AND b.fac_bijlagen_filename = " + safe.quoted_sql(p_flexwaarde);
        }
        else
        {
            sql += (v_flexwaarde > 0 ? " AND b.fac_bijlagen_key = " + v_flexwaarde : "");
        }
    }
    else
    {
        sql += " AND b.fac_bijlagen_refkey = " + p_refkey;
        if (p_module == "MLD" && pNiveau == "M")
        {
            sql += " AND (SELECT CASE WHEN k.mld_kenmerk_niveau IN ('O', 'P') THEN 'O'"
                 + "                  ELSE 'M'"
                 + "             END"
                 + "        FROM mld_kenmerk k"
                 + "       WHERE k.mld_kenmerk_key = b.fac_bijlagen_kenmerk_key"
                 + "     ) = " + safe.quoted_sql(pNiveau);
        }

        if (p_kenmerkkey > 0)
        {
            sql += " AND b.fac_bijlagen_kenmerk_key = " + p_kenmerkkey;
        }
        else // moet pNiveau gezet zijn bij diverse modules
        {
            var sql_kenmerk;
            switch (p_module)
            {
                case "MLD":
                    if (pNiveau == 'M') // melding
                    {
                        if (pkenmerk_geldig) // toon alleen de geldige (bijlage) kenmerken
                            sql_kenmerk = "SELECT k.mld_kenmerk_key"
                                        + "  FROM mld_melding m"
                                        + "     , mld_stdmelding s"
                                        + "     , mld_discipline d"
                                        + "     , mld_kenmerk k"
                                        + "     , mld_srtkenmerk t"
                                        + " WHERE m.mld_stdmelding_key = s.mld_stdmelding_key"
                                        + "   AND s.mld_ins_discipline_key = d.ins_discipline_key"
                                        + "   AND k.mld_srtkenmerk_key = t.mld_srtkenmerk_key"
                                        + "   AND k.mld_kenmerk_verwijder IS NULL"
                                        + "   AND t.mld_srtkenmerk_verwijder IS NULL"
                                        + "   AND t.mld_srtkenmerk_kenmerktype IN ('M', 'F', 'E', 'X')"
                                        + "   AND (  (k.mld_kenmerk_niveau = 'A' AND k.mld_stdmelding_key IS NULL)"
                                        + "       OR (k.mld_kenmerk_niveau = 'S' AND k.mld_stdmelding_key = s.mld_stdmelding_key)"
                                        + "       OR (k.mld_kenmerk_niveau = 'D' AND k.mld_stdmelding_key = s.mld_ins_discipline_key)"
                                        + "       OR (k.mld_kenmerk_niveau = 'T' AND k.mld_stdmelding_key = d.ins_srtdiscipline_key)"
                                        + "       )"
                                        + "   AND m.mld_melding_key = " + p_refkey;
                        else
                            sql_kenmerk = "SELECT mld_kenmerk_key FROM mld_kenmerk WHERE mld_kenmerk_niveau IN ('T', 'D', 'S', 'A')";
                    }
                    else // opdracht
                    {
                        if (pkenmerk_geldig)
                            sql_kenmerk = "SELECT k.mld_kenmerk_key"
                                        + "  FROM mld_opdr o"
                                        + "     , mld_srtkenmerk t"
                                        + "     , mld_kenmerk k"
                                        + " WHERE k.mld_srtkenmerk_key = t.mld_srtkenmerk_key"
                                        + "   AND k.mld_kenmerk_verwijder IS NULL"
                                        + "   AND t.mld_srtkenmerk_verwijder IS NULL"
                                        + "   AND (  (k.mld_kenmerk_niveau = 'P' AND k.mld_typeopdr_key IS NULL)"
                                        + "       OR (k.mld_kenmerk_niveau = 'O' AND k.mld_typeopdr_key = o.mld_typeopdr_key)"
                                        + "       )"
                                        + "   AND t.mld_srtkenmerk_kenmerktype IN ('M', 'F', 'E', 'X')"
                                        + "   AND o.mld_opdr_key = " + p_refkey;
                        else
                            sql_kenmerk = "SELECT mld_kenmerk_key FROM mld_kenmerk WHERE mld_kenmerk_niveau IN ('O', 'P')";
                    }
                    break;
                case "ALG":
                    sql_kenmerk = "SELECT alg_kenmerk_key FROM alg_kenmerk WHERE alg_kenmerk_niveau = " + safe.quoted_sql(pNiveau);
                    break;
                case "BES":
                    sql_kenmerk = "SELECT bes_kenmerk_key FROM bes_kenmerk WHERE bes_kenmerk_niveau = " + safe.quoted_sql(pNiveau);
                    break;
                //case "INS":
                //    sql_kenmerk = "SELECT ins_kenmerk_key FROM ins_kenmerk WHERE ins_kenmerk_niveau = " + safe.quoted_sql(pNiveau);
                //    break;
                case "PRS":
                    sql_kenmerk = "SELECT prs_kenmerk_key FROM prs_kenmerk WHERE prs_kenmerk_niveau = " + safe.quoted_sql(pNiveau);
                    break;
                case "RES":
                    {
                        if (pkenmerk_geldig)
                            sql_kenmerk = "SELECT k.res_kenmerk_key"
                                        + "  FROM res_rsv_ruimte r"
                                        + "     , res_kenmerk k"
                                        + "     , res_srtkenmerk s"
                                        + " WHERE r.res_activiteit_key = k.res_activiteit_key"
                                        + "   AND k.res_srtkenmerk_key = s.res_srtkenmerk_key"
                                        + "   AND k.res_kenmerk_verwijder IS NULL"
                                        + "   AND s.res_srtkenmerk_verwijder IS NULL"
                                        + "   AND s.res_srtkenmerk_kenmerktype IN ('M','F','E','X')"
                                        + "   AND r.res_rsv_ruimte_key = " + p_refkey;
                        else
                            sql_kenmerk = "SELECT res_kenmerk_key FROM res_kenmerk WHERE res_kenmerk_niveau = " + safe.quoted_sql(pNiveau);
                    }
                    break;
            }
            if (sql_kenmerk)
                sql += " AND b.fac_bijlagen_kenmerk_key IN ({0}) ".format(sql_kenmerk);

        }
    }

    var bijlagen = [];
    var oRs = Oracle.Execute(sql);
    while (!oRs.eof)
    {
        var extension = oRs("fac_bijlagen_filename").Value.split(".").pop().toLowerCase();
        var ffile = { key:        oRs("fac_bijlagen_key").Value
                    , diskpath:   oRs("fac_bijlagen_disk_directory").Value
                    , diskname:   oRs("fac_bijlagen_disk_filename").Value
                    , name:       oRs("fac_bijlagen_filename").Value
                    , mimetype:   S("flex_mimetypes")[extension]
                    , date:       new Date(oRs("fac_bijlagen_aanmaak").Value)
                    , size:       oRs("fac_bijlagen_file_size").Value
                    , digest:     oRs("fac_bijlagen_digest").Value
                    , module:     p_module
                    , niveau:     oRs("fac_bijlagen_niveau").Value
                    , refkey:     oRs("fac_bijlagen_refkey").Value
                    , kmkey:      oRs("fac_bijlagen_kenmerk_key").Value
                    , rootkey:    oRs("root_key").Value
                    , rootrefkey: oRs("root_refkey").Value
                    };
        if (ffile.name.match(/_20[0-9]{6}_[0-9]{6}\./))
            ffile.ishistory = true;

        bijlagen.push(ffile);
        oRs.MoveNext();
    }
    oRs.Close();
    __Log("{0} bestand(en) gevonden in fac_bijlagen.".format(bijlagen.length));
    return bijlagen;
}


function DeleteFile(fullpath, km_params)
{
    try
    {
        if (km_params)
        {
            if (km_params.AttachPath)
            {
                if (km_params.files.length)
                {
                    for (var i=0; i<km_params.files.length; i++)
                    {
                        var bijlagen_key = km_params.files[i].key;
                        var bijlagen_naam = km_params.files[i].name;
                        var root_key = km_params.files[i].rootkey;

                        if (km_params.file && km_params.file != bijlagen_naam)
                            continue;

                        if (bijlagen_key == root_key)
                        {   // Het root-record wordt verwijderd.
                            // Haal file gegevens op voor de nieuwe plaats van het bestand en verplaats deze.
                            var sql_d = "SELECT f1.fac_bijlagen_key"
                                      + "     , f1.fac_bijlagen_refkey"
                                      + "     , f1.fac_bijlagen_kenmerk_key"
                                      + "     , f1.fac_bijlagen_disk_directory new_dir"
                                      + "     , f2.fac_bijlagen_disk_directory old_dir"
                                      + "  FROM fac_bijlagen f1"
                                      + "     , fac_bijlagen f2"
                                      + " WHERE f1.fac_bijlagen_root_key = f2.fac_bijlagen_key"
                                      + "   AND f1.fac_bijlagen_key <> f2.fac_bijlagen_key"
                                      + "   AND f1.fac_bijlagen_verwijder IS NULL"
                                      + "   AND f2.fac_bijlagen_key = " + bijlagen_key
                                      + " ORDER BY f1.fac_bijlagen_key ASC";
                            var oRs_d = Oracle.Execute(sql_d);
                            if (!oRs_d.eof)
                            {   // Pas eventueel de verwijzing via root_key aan.
                                // De disk_directory wordt ook aangepast voor een record dat de nieuwe root wordt.
                                var sql_d = "BEGIN"
                                          + "  flx.deleteflexbijlage(" + bijlagen_key + ");"
                                          + "END;";
                                Oracle.Execute(sql_d);
                            }
                            else
                            {   // Er zijn geen verwijzingen dus maar gelijk verwijderen.
                                var old_dir = km_params.files[i].diskpath;
                                var v_path = km_params.AttachRootPath + "/" + old_dir + "/" + bijlagen_naam;
                                try {
                                    fso.DeleteFile(v_path, true);
                                } catch (e) {
                                    if (e.description === "File not found") {
                                        __DoLog("Verwijderen " + fullpath + " mislukt: " + e.description, "#FFFF00");
                                        // Laat de code dan maar gewoon doorlopen,
                                        // als het bestand niet bestaat willen we deze verwijzing toch verwijderen
                                    } else {
                                        throw e;
                                    }
                                }
                                // Ook uit fac_bijlagen verwijderen.
                                var sql_d = "BEGIN"
                                          + "  flx.deleteflexbijlage(" + bijlagen_key + ", TRUE);"
                                          + "END;";
                                Oracle.Execute(sql_d);
                            }
                            oRs_d.Close();
                        }
                        else
                        {   // Deze bijlage kan er gewoon tussenuit gehaald worden.
                            var sql_d = "BEGIN"
                                      + "  flx.deleteflexbijlage(" + bijlagen_key + ");"
                                      + "END;";
                            Oracle.Execute(sql_d);
                        }
                    }
                }
                else
                {
                    if (km_params.file)
                    {
                        var v_path = km_params.AttachPath + km_params.file;
                        fso.DeleteFile(v_path, true);

                        if ("linkImmediate" in km_params && pKey > 0) { // Unlink dit bestand ook van de entiteit waar het bij hoort in de DB
                            updateLinkedFilename(km_params.refkey, km_params);
                        }

                        if (km_params.fac_bijlagen) {
                            // Pas eventueel de verwijzing via root_key aan.
                            // En verwijder het record daarna echt.
                            var sql_d = "BEGIN"
                                    + "  flx.deleteflexbijlage"
                                        + "(" + safe.quoted_sql(km_params.module)
                                        + "," + km_params.kenmerkkey
                                        + "," + km_params.refkey
                                        + "," + safe.quoted_sql(km_params.AttachSubPath)
                                        + "," + safe.quoted_sql(km_params.file)
                                        + ");"
                                    + " DELETE FROM fac_bijlagen"
                                    + "  WHERE fac_bijlagen_module = " + safe.quoted_sql(km_params.module)
                                    + "    AND fac_bijlagen_kenmerk_key = " + km_params.kenmerkkey
                                    + "    AND fac_bijlagen_refkey = " + km_params.refkey
                                    + "    AND fac_bijlagen_disk_directory = " + safe.quoted_sql(km_params.AttachSubPath)
                                    + "    AND fac_bijlagen_filename = " + safe.quoted_sql(km_params.file)
                                    + "    AND fac_bijlagen_verwijder IS NOT NULL;"
                                    + "END;";
                            Oracle.Execute(sql_d);
                        }
                    }
                }
            }

            if (km_params.with_folder)
            {
                var fsoFile = fso.GetFile(fullpath);
                fso.DeleteFolder(fsoFile.ParentFolder);
            }
        }
        else
        {
            fso.DeleteFile(fullpath, true);
        }
    }
    catch (e)
    {
        __DoLog("Verwijderen " + fullpath + " mislukt: " + e.description, "#FFFF00");
    };
}

// Verplaats nieuwe bb-bijlages
function move_new_bb_files(module, refkey, bb_files) {
  var bb_files = bb_files || [];
  if (bb_files.length) {
    var fso = Server.CreateObject("Scripting.FileSystemObject");
    var newProps = flexProps(module);
    var props = flexProps(module, refkey);
    try {
      for (var i = 0; i < bb_files.length; i++) {
        var filename = bb_files[i];
        if (fso.fileExists(newProps.AttachPath + filename)) {
          CreateFullPath(props.AttachPath);
          fso.MoveFile(newProps.AttachPath + filename, props.AttachPath + filename);
          var sql = "UPDATE fac_bijlagen"
                  + "   SET fac_bijlagen_refkey = " + refkey
                  + "     , fac_bijlagen_disk_directory = " + safe.quoted_sql(props.AttachSubPath)
                  + " WHERE fac_bijlagen_refkey = -1"
                  + "   AND fac_bijlagen_filename = " + safe.quoted_sql(filename)
                  + "   AND fac_bijlagen_disk_directory = " + safe.quoted_sql(newProps.AttachSubPath);
          Oracle.Execute(sql);
        }
      }
      fso.DeleteFolder(newProps.AttachPath.slice(0, -1));
    } catch (e) {
        __DoLog("move_new_bb_files van " + newProps.AttachPath + " naar " + props.AttachPath + " mislukt: " + e.description);
    }
  }
}

// Verplaats alle bestanden van één folder
// Verplaatst geen subfolders
function MoveFlexfiles(vAttachPath, vAttachPath2)
{
    if (vAttachPath == vAttachPath2)
    {
        __Log("MoveFlexfiles Skip want twee keer " + vAttachPath);
        return;
    }

    try
    {
        var fso = Server.CreateObject("Scripting.FileSystemObject")
        __Log("Zoeken " + vAttachPath);
        if (fso.FolderExists(vAttachPath))
        {
            var oFolder = fso.GetFolder(vAttachPath);
            if (oFolder.files.count > 0) // Anders error
            {
                CreateFullPath(vAttachPath2); // het 1000-tal was er misschien nog niet.
                __Log("Verplaats inhoud " + vAttachPath + "/*.* naar " + vAttachPath2 + "/");
                fso.MoveFile (vAttachPath + "/*.*", vAttachPath2 + "/");
            }
            fso.DeleteFolder(vAttachPath);
        }
    }
    catch(ee)
    {
        __DoLog("Moving files from " + vAttachPath + "<br>to " + vAttachPath2 + " failed:<br>" + ee.description, "#FFFF00");
    }
    fso = null;
}

function OpenFlexFile(module, bijlagen_key, params)
{   // params kan bevatten
    //  name: <naam van het bestand> voor als deze niet in fac_bijlagen is opgenomen, bv: bestanden uit module CUSTTEMPPUO
    //  mime_type: "image/png"
    //  contentdp: "attachment"
    params = params || {};
    var s = HTTP.urlzelfnoroot() + rooturl + "/appl/shared/BijlagenStream.asp"
    s += "?bijlagen_key=" + bijlagen_key
      + "&module=" + module
      + (params.niveau ? "&niveau=" + params.niveau : "")
      + (params.kenmerk_key > 0 ? "&kenmerk_key=" + params.kenmerk_key : "");

    if (params.key > 0)
        s += "&key=" + params.key;
    if (params.tmpfolder && params.tmpfolder != "")
        s += "&tmpfolder=" + safe.url(params.tmpfolder);
    if (params.name)
        s += "&filename=" + safe.url(params.name);
    if (params.mime_type)
        s += "&mime=" + params.mime_type;
    if (params.contentdp)
        s += "&contentdp=" + params.contentdp;
    if (params.dosave)
        s += "&dosave=" + params.dosave;
    return s;
}

// JavaScript is erg slecht in binary data, gebruik streams
// gebaseerd op Antonin Foller, http://www.motobit.com
// Binary - VT_UI1 | VT_ARRAY data To convert To a string
// getest met encoding "bin.hex" en "bin.base64"

function encodedString2File(safefullname, attachmentString, encoding)
{
    __Log("Saving {0} file to {1}".format(encoding, safefullname));
    var BinaryStream = XXXXDecode(attachmentString, encoding);
    BinaryStream.SaveToFile(safe.UNC(safefullname), 2); // adSaveCreateOverWrite
}

function XXXXDecode(vCode, encoding)
{
    var oXML, oNode

    oXML = new ActiveXObject("Msxml2.DOMDocument.6.0");
    oNode = oXML.createElement("encodeddata");
    oNode.dataType = encoding; // Zeer snelle oplossing
    oNode.text = vCode
    var Binary = oNode.nodeTypedValue;
    var adTypeText = 2;
    var adTypeBinary = 1;

    // Create Stream object
    var BinaryStream = new ActiveXObject("ADODB.Stream");

    // Specify stream type - we want To save binary data.
    BinaryStream.Type = adTypeBinary;

    // Open the stream And write binary data To the object
    BinaryStream.Open();
    BinaryStream.Write(Binary);

    // Change stream type To text/string
    BinaryStream.Position = 0;
    BinaryStream.Type = adTypeText;

    // Specify charset For the output text (unicode) data.
    BinaryStream.CharSet = "us-ascii";

    // Open the stream And get text/string data from the object
    return BinaryStream;
}

// Kijkt of bestand met naam fileName al bestaat in newFolder
// en returnt een 'bestand.exe' dan in de variant 'bestand (2).exe'
function uniqueFileName(newFolder, fileName) {
    if (fso.FolderExists(newFolder)) {
        var multiFileCount = 2;
        var extension = fileName.split(".").pop();
        var multiRegex = new RegExp("(\\s\\(\\d+\\))?\\." + extension + "$", "i");
        while (fso.fileExists(newFolder + "/" + fileName) && multiFileCount < 1000) {
            fileName = fileName.replace(multiRegex, " (" + multiFileCount++ + ")." + extension);
        }
        if (multiFileCount === 1000) {
            __DoLog("Er kon geen unieke naam gevonden worden voor dit bestand want zelfs " + fileName + " bestaat al", "#FF0000");
            fileName = fileName.replace(multiRegex, "_" + shared.random(32) + "." + extension);
            return fileName; // Dan maar met een random string
        }
    }
    return fileName;
}

function getFilesize(safefullpath)
{
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var sz = -1;
    if (fso.FileExists(safefullpath))
    {
        var fsoFile = fso.GetFile(safefullpath);
        sz = fsoFile.Size;
    }
    return sz;
}

// Haal de filenaam van de bijlage op
function getLinkedFilename(key, props) {
    var result = "";
    if (props.linkImmediate) {
        var sql = "SELECT " + props.linkImmediate.link_col
                + "  FROM " + props.linkImmediate.table
                + " WHERE " + props.linkImmediate.key_col + " = " + key;
        var oRs = Oracle.Execute(sql);
        if (!oRs.EoF) {
            result = oRs(0).Value;
        }
        oRs.Close();
    }
    return result;
}

// Update het DB-record van de bijlage, laat newSafeFilename leeg om DB-veld leeg te maken
function updateLinkedFilename(key, props, newSafeFilename) {
    var sql = "UPDATE " + props.linkImmediate.table
            + "   SET " + props.linkImmediate.link_col + " = " + (newSafeFilename ? safe.quoted_sql(newSafeFilename) : "NULL")
            + " WHERE " + props.linkImmediate.key_col + " = " + key;
    Oracle.Execute(sql);
    return newSafeFilename;
}

function copyLinkedFile(module, old_key, new_key) {
    var props = flexProps(module);
    var filename = getLinkedFilename(old_key, props);
    if (!filename) {
        return;
    }
    var safeFilename    = safe.filename(filename);
    var newSafeFilename = uniqueFileName(props.AttachPath, safeFilename);
    var safeFullPath    = props.AttachPath + safeFilename;
    var newSafeFullPath = props.AttachPath + newSafeFilename;
    if (fso.FileExists(safeFullPath)) {
        try {
            fso.CopyFile(safeFullPath, newSafeFullPath);
            if (fso.FolderExists(props.AttachPath + "/thumb/") && fso.FileExists(props.AttachPath + "/thumb/" + safeFilename)) {
                var safeFullThumbPath    = props.AttachPath + "/thumb/" + safeFilename;
                var newSafeFullThumbPath = props.AttachPath + "/thumb/" + newSafeFilename;
                fso.CopyFile(safeFullThumbPath, newSafeFullThumbPath);
            }
        } catch (e) {
            __DoLog("ERROR copying " + safeFullPath + "/" + safeFilename + " -> " + newSafeFullPath + "/" + newSafeFilename, "#FF0000");
            __DoLog(e.description);
            return;
        }
        return updateLinkedFilename(new_key, props, newSafeFilename);
    }
    return;
}

// Zip een enkele file (met SLNKDWF.Zip)
function zipfile(fullpath, filename)
{
    var oZIP = new ActiveXObject("SLNKDWF.Zip");
    var fso = new ActiveXObject("Scripting.FileSystemObject");
    var temp = shared.tempFolder() + "/" + fso.GetTempName();
    var iStream = new ActiveXObject("ADODB.Stream")
    iStream.Type = 2; // Text
    iStream.Open();
    iStream.CharSet = "utf-8";
    try
    {
        iStream.LoadFromFile(safe.UNC(fullpath));
    }
    catch (e)
    {
        shared.simpel_page("Error opening " + Server.HTMLEncode(fullpath) + "<p></p><em>"+e.description+"</em>");
    }
    oZIP.New(temp) //;; Helaas niet *naar* stream
    oZIP.ZipFromStream(filename, iStream);
    oZIP.Close();
    iStream.Close()
    var oStream = new ActiveXObject("ADODB.Stream");
    oStream.Open;
    oStream.Type = 1; // adTypeBinary

    oStream.LoadFromFile(safe.UNC(temp));
    oStream.Position = 0;
    fso.DeleteFile(temp);
    Response.clear;
    Response.contenttype = 'application/zip';
    Response.AddHeader("content-disposition", "attachment; filename= \"" + filename + ".zip\"");
    Response.BinaryWrite(oStream.read(oStream.Size));
    Response.End;
}

// Zip meerdere fac_bijlagen naar een enkel bestand (met Chilkat.zip)
// files mag zijn:
// -->A) Array van [fac_bijlagen_key] (dan komen ze allemaal in de root van de zipfile met hun eigen naam)
// -->B) Array van [{ fac_bijlagen_key: fac_bijlagen_key, zippath: "path-in-zip/name-in-zip" }]
function zipfacbijlagen(targetname, files)
{
    var allfiles = [];
    for (var i = 0; i < files.length; i++)
    {
        var file = files[i];
        if (typeof file == "number")
        {
            var bijlagen_key = file;
            var newfile = { "fac_bijlagen_key": file };
        }
        else
        {
            bijlagen_key = file.fac_bijlagen_key;
            newfile = file;
        }

        var sql = "SELECT fac_bijlagen_filename, "
                + "       fac_bijlagen_disk_directory, "
                + "       disk_filename"
                + "  FROM fac_v_bijlagen"
                + " WHERE fac_bijlagen_key = " + bijlagen_key;
        var oRs = Oracle.Execute(sql);

        newfile.filepath = S("flexfilespath") + "/" + oRs("fac_bijlagen_disk_directory").Value + "/" + oRs("disk_filename").Value;
        oRs.Close()
        allfiles.push(newfile);
    }
    return zipfiles(targetname, allfiles);
}

// Zip meerdere files naar een enkel bestand
// files moet zijn:
// -->C) Array van [{ filepath: webserver-path-to-source-file, zippath: "path-in-zip" }]
// de zippath is optioneel en moet dan path/to/filename.ext zijn (in de zip)

// Een bestaande zip wordt wel toegevoegd maar precies zoals wel willen:
// The default "no compress" extensions are: .zip, .gif, .jpg, .gz, .rar, .jar, .tgz, .bz2, .z, .rpm, .msi, .png
// Daar hoeven we ons dus niet druk over te maken
function zipfiles(targetname, files)
{
    __Log(files);
    var glob = new ActiveXObject("Chilkat_9_5_0.Global")
    var success = glob.UnlockBundle(S("puo_chilkat_secret"));
    if (success != 1)
        throw { description: glob.LastErrorText };

    var zip = new ActiveXObject("Chilkat_9_5_0.Zip");

    var success = zip.NewZip("facilitor.zip"); // nog in memory
    if (!success)
        throw { description: zip.LastErrorText };

    var uncompressed = 0;
    for (var i = 0; i < files.length; i++)
    {
        var file = files[i];
        if (!fso.FileExists(file.filepath))
        {
            __DoLog("Zipping: {0} not found".format(file.filepath));
            continue;
        }
        var success = zip.AppendOneFileOrDir(file.filepath,0/*saveExtraPath*/);
        if (!success)
            throw { description: zip.LastErrorText };
        var lastEntry = zip.GetEntryByIndex(zip.NumEntries - 1);
        uncompressed += lastEntry.UncompressedLength;
        if (file.zippath)
        {
            lastEntry.FileName = file.zippath;
        }
    }
    if (uncompressed > 1024*1024*S("max_report_zip_uncompressed"))
    {
        shared.simpel_page(L("lcl_zip_bijlagen_exceeded").format(Math.round(uncompressed/1024/1024), files.length, S("max_report_zip_uncompressed")));
    }

    Response.Clear(); // Het zou trouwens raar zijn als hij niet clear was?
    Response.Buffer = false; // Geen buffering nodig. Bovendien kunnen we nu ook bestanden
                             // groter dan de ResponseBuffersize aan

    Response.contenttype = 'application/zip';
    Response.AddHeader("content-disposition", "attachment; filename= \"" + targetname + "\"");

    __Log("Zipping {0} uncompressed bytes".format(uncompressed));
    // Echt helemaal streaming kan ik niet vinden
    // Chilkat_9_5_0.StreamConnector schijnt alleen bij de .NET interface te bestaan
    var bindata = new ActiveXObject("Chilkat_9_5_0.BinData");
    var success = zip.WriteBd(bindata);
    if (!success)
        throw { description: zip.LastErrorText };
    __Log("Zipfile is {0} bytes ({1}%)".format(bindata.numBytes, Math.round(100 * bindata.numBytes / uncompressed)));
    var CHUNKSIZE = 1024*1024; // zelfs met Response.Buffer==false
    for (var chunk = 0; chunk * CHUNKSIZE < bindata.numBytes; chunk++)
    {
        Response.BinaryWrite(bindata.GetBinaryChunk(chunk * CHUNKSIZE, CHUNKSIZE));
    }
    __Log("Written in {0} chunks".format(chunk - 1));

//    var fac = new ActiveXObject("Chilkat_9_5_0.FileAccess");
//    var success = fac.WriteEntireFile("c:\\temp\\test.zip",zipFileInMemory);
//    if (!success)
//        throw { description: fac.LastErrorText };
//    }
}
%>
