// ******************************************
// * $Id$
// *
// *   sendMail()
//*
// * sendMail function is used to send mail
// *         If the OrderInMailBody is set the attachment will be added to the body
// *
// * arguments:
// *           p_mailfrom: The address the mail is sent from (system if "") or must be replied to
// *             p_mailto: The address where the mail is sent to
// *            p_subject: The subject of the mail
// *               p_body: The body of the mail if the OrderInMailBody is not set
// *           p_bodyhtml: The body of the mail if the OrderInMailBody is not set
// * params:
// *     attachFileName: Filenaam van de attachment als hele body als attachement wordt gestuurd
// *     attachPassword: Encrypt(zip) elke attachment met dit wachtwoord als niet leeg
// *       attachStream: Datastream waarin de attachment zit
// *       include_file: Deze file toevoegen (gezocht onder S("bdradrfiles_path"))
// *                 cc: The cc address
// *                bcc: The bcc address
// *          receiptto: The address where the receipt is sent to
// *          attachics: deze tekst moet als ics toegevoegd worden
// *       bedrijfadres:
// *       module      :
// *       niveau      :
// *       refkey      :
// *       kenmerk_key :
// *
// ******************************************
function sendMail( p_mailfrom
                 , p_mailto
                 , p_subject
                 , p_body
                 , p_bodyhtml
                 , params
                 )
{
    Log2File(2, "*> sendMail");
    params = params || {};

v_aanduiding = "sendMail 1";
    if (S("puo_forcemailaddress") == "donotsend@facilitor.nl")
    {
        Log2File(1, "E-mail forced to 'donotsend@facilitor.nl' will not be actually sent");
        return true;
    }

    var objFso  = new ActiveXObject("Scripting.FileSystemObject");
    var objStrm = new ActiveXObject("ADODB.Stream");
    var objMail = new ActiveXObject("CDO.Message");
    var oCrypto = new ActiveXObject("SLNKDWF.Crypto");

    // De onderstaande configuratie is ook handig voor het testen op een lokale pc.
    // Dan heb je geen lokale SMTP service nodig
	if (S("puo_sendusing") == 2) // cdoSendUsingPort
	{
        var objConf =  new ActiveXObject("CDO.Configuration");
	    var sch = "http://schemas.microsoft.com/cdo/configuration/"
	    objConf.Fields(sch + "sendusing").Value = S("puo_sendusing"); // 1=cdoSendUsingPickup, 2=cdoSendUsingPort
	    objConf.Fields(sch + "smtpserver").Value = S("puo_smtpserver"); // Wel voor ons IP-adres relay toestaan!
	    objConf.Fields(sch + "smtpserverport").Value = S("puo_smtpserverport"); //  default 25
	    objConf.Fields(sch + "smtpconnectiontimeout").Value = S("puo_smtpconnectiontimeout"); //  default 30
	    if (S("puo_smtpusessl"))
	    {
	      objConf.Fields(sch + "smtpusessl").Value = true;
	    }
	    objConf.Fields(sch + "smtpauthenticate").Value = S("puo_smtpauthenticate"); // default 0=cdoAnonymous, 1=cdoBasic, 2=cdoNTLM
	    if (S("puo_smtpauthenticate") == 1)
	    {
	        objConf.Fields(sch + "sendusername").Value = S("puo_sendusername");
	        objConf.Fields(sch + "sendpassword").Value = S("puo_sendpassword");
	    }
	    objConf.Fields.Update();
        objMail.Configuration = objConf;
	}
    //
v_aanduiding = "sendMail 2";

    Log2File(3, "In SendMail sender=" + p_mailfrom);
    var Mailsend = false;

    var MailSender = S("puo_fromaddress");
    var MailReply = S("puo_replyaddress");
    if (p_mailfrom)
    {
        if (S("puo_usesenderasreplyto"))
        {
            // the sytem is the sender, but replies go to the sender
            MailSender = S("puo_fromaddress");
            MailReply = p_mailfrom;
        }
        else
        {
            // The sender is the real sender
            MailSender = p_mailfrom;
            MailReply = "";
        }
    }
    if (params.replyTo)
        MailReply = params.replyTo
v_aanduiding = "sendMail 2a";

    // Vanuit puo_allorders.js -> puo_sendfile.js/connectMail() is het object bedrijfadres beschikbaar
    // Laatste overrule voor als bij het bedrijf een afzender- of reply-adres is ingevuld.
    if (params.bedrijfadres)
    {
        if (params.bedrijfadres.sender)
            MailSender = params.bedrijfadres.sender;
        if (params.bedrijfadres.reply)
            MailReply = params.bedrijfadres.reply;
    }

    if (!p_mailto || !MailSender)
    {
        Log2File(1, "Email not sent because from or to is empty.");
    }
    else
    {
v_aanduiding = "sendMail 2b";
        if (p_body)
        {
v_aanduiding = "sendMail 2c";
            if (params.bedrijfadres && params.bedrijfadres.charset)
                objMail.BodyPart.Charset = params.bedrijfadres.charset; // Forceren

            objMail.TextBody = p_body;
            if (p_bodyhtml)
            {
v_aanduiding = "sendMail 2d";
                // Als attachment er bij
                var cdoBodyPart = objMail.BodyPart.AddBodyPart(-1);
                cdoBodyPart.ContentMediaType = "text/html";
                cdoBodyPart.ContentTransferEncoding = "7bit";
                objStrm = cdoBodyPart.GetDecodedContentStream();
                objStrm.Charset = 'Windows-1252';
                objStrm.WriteText(p_bodyhtml);
                objStrm.Flush();
                objStrm.Close();
                var objFlds = cdoBodyPart.Fields;
                objFlds("urn:schemas:mailheader:content-disposition").Value = "attachment; filename=\"" + params.attachFileName + "\"";
                objFlds.Update();
            }
        }
        else
        {
            // Geen p_body, dus dan moet p_bodyhtml gezet zijn.
v_aanduiding = "sendMail 2e";
            try
            {   // Zowel textbody als htmlbody zetten opdat default Android e-mail client
                // het euro teken goed doet.
                // NEEN: Dan zijn er mail-clients die de HTML (terecht) tonen vanwege content-type text/plain
                // objMail.TextBody = p_bodyhtml;
                // objMail.TextBodyPart.Charset = S("puo_mailbodycharset"); // default "unicode-1-1-utf-8
                objMail.BodyPart.Charset = S("puo_mailbodycharset"); // default "unicode-1-1-utf-8
                var rnd_cid, cidname;
                Log2File(2, "Before bodyHTML");
v_aanduiding = "sendMail 2f";

                var startPos = p_bodyhtml.indexOf("cid:") + 4;
                var has_type = p_bodyhtml.substr(startPos).match(/\.gif|\.png|\.jpg|\.jpeg/);
                var eindPos = ( has_type
                              ? p_bodyhtml.indexOf(has_type[0], startPos) + has_type[0].length
                              : startPos
                              );
                if (startPos >= 4 && eindPos > startPos && eindPos - startPos < 40)
                {
v_aanduiding = "sendMail 2g";
                    var logoFileName = p_bodyhtml.substring(startPos, eindPos);
                    var logoPathName = custabspath + "/" + logoFileName;

                    if (objFso.FileExists(logoPathName))
                    {
                        Log2File(2, logoFileName);
                        rnd_cid = oCrypto.hex_random(10);
                        cidname = "logo" + rnd_cid + ".gif";
                        p_bodyhtml = p_bodyhtml.substr(0, startPos - 4) + "cid:" + cidname + p_bodyhtml.substr(eindPos);

v_aanduiding = "sendMail 2h";
                        try {
                            objMail.addRelatedBodyPart(logoPathName, cidname, 0);
                        }
                        catch (e)
                        {
                            throw new UserException(e + 1000, "PutOrders", e.description + "\nPerhaps invalid logo path: "+ logoPathName);
                        }
                    }
                    else
                    {
                        Log2File(1, "Warning: logo '" + logoPathName + "' not found. Ignoring.");
                    }
                }

                // qrc="https://aasa.facilitor.nl/?mobile=1&amp;u=opdracht&amp;k=32751" wordt omgezet naar
                // src="cid:qrc.png"
                // Ondertussen is het al HTML dus we kunnen geen XML-query doen
                // Daarom gewoon textueel opzoeken

v_aanduiding = "sendMail 2i";
                startPos  = p_bodyhtml.indexOf("qrc=") + 4;
                var imgstart = p_bodyhtml.lastIndexOf("<img", startPos); // moet wel binnen een <img> vallen
                var imgend   = p_bodyhtml.indexOf(">", imgstart);
                var quote = p_bodyhtml.substr(startPos, 1); // enkele of dubbele quote
                eindPos   = p_bodyhtml.indexOf(quote, startPos + 2);
                if (startPos > 3 && eindPos > startPos && imgstart > 0 && imgend > startPos)
                {
v_aanduiding = "sendMail 2j";
                    var qrc = p_bodyhtml.substring(startPos + 1, eindPos);
                    qrc = qrc.replace(/\&amp;/g, "&"); // Het was nog HTML/XML-encoded
                    var xc = new ActiveXObject("SLNKDWF.QRCode");
                    xc.Text = qrc;
                    Log2File(2, "Creating QRC: " + qrc);
                    var oStream = new ActiveXObject("ADODB.Stream");
                    oStream.Open;
                    oStream.Type = 1; // binary
                    oStream.Write(xc.GetAsPNG());
                    var sha1 = oCrypto.hex_sha1(qrc);
                    var tempfile = custabspath + "/../../temp/" + customerId + "/puo_qr_" + sha1 + ".png";
                    oStream.SaveToFile(tempfile, 2); // overwrite
                    rnd_cid = oCrypto.hex_random(10);
                    cidname = "qrc" + rnd_cid + ".png";
                    p_bodyhtml = p_bodyhtml.substr(0, startPos - 4) + "src=\"cid:" + cidname + "\"" + p_bodyhtml.substr(eindPos + 1);
                    objMail.addRelatedBodyPart(tempfile, cidname, 0);
                    if (S("puo_loglevel") < 4)
                        objFso.DeleteFile(tempfile);
                }

                // Nu frc-codering opzoeken <img frc="M=SML:K=34417"/>
                startPos = p_bodyhtml.indexOf("frc=") + 4;
                var imgstart = p_bodyhtml.lastIndexOf("<img", startPos); // moet wel binnen een <img> vallen
                var imgend   = p_bodyhtml.indexOf(">", imgstart);
                quote    = p_bodyhtml.substr(startPos, 1); // enkele of dubbele quote
                eindPos  = p_bodyhtml.indexOf(quote, startPos + 2);
                while (startPos > 4 && eindPos > startPos && imgstart > 0 && imgend > startPos)
                {
v_aanduiding = "sendMail 2k";
                    var flexcode = p_bodyhtml.substring(startPos + 1, eindPos);
                    if (flexcode.indexOf("M=") < 0)
                    {
                        Log2File(1, "<img frc=...> found in XML but invalid. Ignored: " + flexcode);
                        break;
                    }
                    if (!S("puo_fclt_web_url") || !S("puo_fclt_web_apikey"))
                    {
                        Log2File(1, "<img frc=...> found in XML but puo_fclt_web_url or puo_fclt_web_apikey not set. Ignored: " + flexcode);
                        break;
                    }

                    // om te voorkomen dat je elke klant in de hosts file moet opnemen wordt
                    // aaxx.facilitor.nl ondersteund, daarom fac_id erbij
                    var fac_web_url = S("puo_fclt_web_url") + "?fac_id=" + customerId;
                    var url = "{0}&API=GETFLEX&APIKEY={1}&flexcode={2}".format(fac_web_url, S("puo_fclt_web_apikey"), flexcode);

                    Log2File(2, url);

                    if (flexcode.match(/^M=CAD/)) // Die roepen we gewoon on-the-fly op
                    {
                        // <xsl:element name="img">
                        //   <xsl:attribute name="frc">M=CAD&amp;labelPos=2&amp;vKey=<xsl:value-of select="//afspraak/plaats/regio/district/locatie/gebouw/verdieping/key"/>&amp;highlight=<xsl:value-of select="//afspraak/plaats/regio/district/locatie/gebouw/verdieping/ruimte/key"/>&amp;mode=0&amp;discs=981&amp;sizeX=700&amp;sizeY=400&amp;offsetX=10&amp;offsetY=10&amp;scale=950&amp;paperColor=16777215
                        //   </xsl:attribute>
                        // </xsl:element>
                        props = {
                            files: [{
                                        resized: url.replace(/\&amp\;/g, "&")
                                    }
                                   ]
                        }
                    }
                    else
                    {
                        var http_request = doHTTP(url, { method: "GET", headers: { "accept": "application/json" }});

                        var props = eval('(' + http_request.responseText + ')');
                        if ("message" in props)
                        {
                            Log2File(1, props.message); // bijvoorbeeld "Invalid APIKEY"
                        }
                    }
                    if (props.flexlog)
                        Log2File(1, props.flexlog);
                    if (!props.files || !props.files.length)
                    {   // Geen bestanden gevonden? Dan hele img-tag gewoon er uit halen
                        eindPos =  p_bodyhtml.indexOf(">", startPos + 2);
                        var backPos = p_bodyhtml.substr(0, startPos).lastIndexOf("<");
                        var newbody = p_bodyhtml.substr(0, backPos) + p_bodyhtml.substr(eindPos + 1);
                        p_bodyhtml = newbody;
                        }
                    else
                    {
                        var fileIndex = 0;
                        if (props.files.length > 1) {
                            var codes = flexcode.split(":");
                            for (var i = 0; i < codes.length && !fileIndex; i++) {
                                var code = codes[i].substr(0,1);
                                var data = codes[i].substr(2);
                                if (code == "F") { // Dan is; data = filename
                                    for (var j = 0; j < props.files.length; j++) {
                                        if (props.files[j].name == data) {
                                            fileIndex = j;
                                            break;
                                        }
                                    }
                                }
                            }
                        }

                        var filedata = props.files[fileIndex];
                        if (filedata.resized)
                            var file = filedata.resized;
                        else
                            var file = props.AttachPath + filedata.name;
                        rnd_cid = oCrypto.hex_random(10);
                        cidname = "flex" + rnd_cid + ".png";
                        p_bodyhtml = p_bodyhtml.substr(0, startPos - 4) + "src=\"cid:" + cidname + "\"" + p_bodyhtml.substr(eindPos + 1);
                        try {
                            objMail.addRelatedBodyPart(file, cidname, 0);
                        }
                        catch (e)
                        {   // Overrule.SET("puo_fclt_web_url", "http://facws001/branch20163/"); vergeten?
                            throw new UserException(e + 1000, "PutOrders", e.description + "\nPerhaps invalid flex path: {0}\nurl was {1}\nflexcode was {2}".format(file, fac_web_url, flexcode));
                        }
                        if (filedata.tempdelete)
                            objFso.DeleteFile(filedata.tempdelete);
                    }
                    // Volgende zoeken
                    startPos = p_bodyhtml.indexOf("frc=", eindPos) + 4;
                    imgstart = p_bodyhtml.lastIndexOf("<img", startPos); // moet wel binnen een <img> vallen
                    imgend   = p_bodyhtml.indexOf(">", imgstart);
                    quote    = p_bodyhtml.substr(startPos, 1);
                    eindPos  = p_bodyhtml.indexOf(quote, startPos + 2);
                }

                // Eventueel een ics er aan toevoegen
                if (params.attachics)
                {
v_aanduiding = "sendMail 2l";
                    Log2File(2, "Adding calendar ICS");
                    var oStream = new ActiveXObject("ADODB.Stream");
                    oStream.Open;
                    oStream.Type = 2; // tekst
                    oStream.Charset = 'Windows-1252'; // Anders is de ics 'not supported'
                    oStream.WriteText(params.attachics);
                    // var sha1 = oCrypto.hex_sha1(params.attachics); werkt niet goed als RESMAI twee keer wordt gestuurd, dan heb je overlap
                    var sha1 = oCrypto.hex_random(16);
                    var tempfile = custabspath + "/../../temp/" + customerId + "/puo_ics_" + sha1 + ".ics";
                    oStream.SaveToFile(tempfile, 2); // overwrite

                    var objAttachment = objMail.AddAttachment(tempfile);
                    objAttachment.ContentTransferEncoding = "base64";
                    objAttachment.ContentMediaType = 'text/calendar; charset="utf-8"; method=REQUEST';
                    objAttachment.ContentClass = 'urn:content-classes:calendarmessage';
                    var Flds = objAttachment.Fields;
                    Flds("urn:schemas:mailheader:content-disposition").Value = "";
                    Flds.Update();

                    if (S("puo_loglevel") < 4)
                        objFso.DeleteFile(tempfile);
                }
                objMail.HtmlBody = p_bodyhtml.replace(/\<br/g, "\x0D\x0A<br"); // FSN#36318 Geen afsluitende '>'
                objMail.HTMLBodyPart.Charset = S("puo_mailbodycharset");
                Log2File(2, "After bodyHTML");
            }
            catch(e)
            {
                throw new UserException(e + 1000, "PutOrders", e.description);
            }
        }
v_aanduiding = "sendMail 3";

        var allAttachSize = 0;
        if (params.include_file) // deze meesturen, bijvoorbeeld algemene voorwaarden
        {
            var safename = safe.filename(params.include_file);
            if (objFso.FileExists(S("bdradrfiles_path") + "/" + safename))
            {
                var attFile = objFso.GetFile(S("bdradrfiles_path") + "/" + safename);
                allAttachSize += attFile.Size;
                Log2File(1, "Including fixed attachment " + S("bdradrfiles_path") + "/" + safename + " (" + attFile.Size + " bytes)");
                var objAttachment = objMail.AddAttachment(S("bdradrfiles_path") + "/" + safename);
                objAttachment.ContentTransferEncoding = "base64";
            }
            else
            {
                Log2File(1, "Warning: fixed attachment '" + S("bdradrfiles_path") + "/" + safename + "' not found. Ignoring.");
            }
        }

v_aanduiding = "sendMail 4";
        if (params.include_cust_file) // volledig pad, bijvoorbeeld temp-xlsx
        {
            var attFile = objFso.GetFile(params.include_cust_file);
            allAttachSize += attFile.Size;
            Log2File(1, "Including custom file " + params.include_cust_file + " (" + attFile.Size + " bytes)");
            var objAttachment = objMail.AddAttachment(params.include_cust_file);
            // deze werkt niet objAttachment.Filename = params.attachFileName;
            objAttachment.Fields.Item("urn:schemas:mailheader:content-disposition").Value ="attachment;filename=" + params.attachFileName;
            objAttachment.Fields.Update();
            objAttachment.ContentTransferEncoding = "base64";
            if (params.tempdelete)
                objFso.DeleteFile(params.include_cust_file); // objMail houdt hem nog even gelocked maar straks is hij wel weg

        }

v_aanduiding = "sendMail 5";
        if (params.attachments_path) // Geselecteerde bestanden uit flexfiles meesturen.
        {   // Voor backwards compatibiliteit weer toegevoegd.
            Log2File(2, "geselecteerde backwards compatibiliteit attachments meesturen");
            for (i=0; i<params.attachments_path.length; i++)
            {
                var att = params.attachments_path[i];
                if (att.substr(att.length-2) == "/*")
                {   // Alle bestanden uit deze map als attachment toevoegen
                    var att_f = S("flexfilespath") + "/" + att.substr(0, att.length-2);
                    if (objFso.FolderExists(att_f))
                    {
                        var objFiles = objFso.GetFolder(att_f);
                        var allFiles = new Enumerator(objFiles.files);
                        //Log2File(1, "Adding all " + objFiles.files.count + " files as attachment from folder: " + att_f);
                        for (; !allFiles.atEnd(); allFiles.moveNext())
                        {
                            var attFile = allFiles.item();
                            allAttachSize += attFile.Size;
                            Log2File(1, "Adding attachment: " + attFile.Path + " (" + attFile.Size + " bytes)");
                            var objAttachment = objMail.AddAttachment(attFile.Path);
                            objAttachment.ContentTransferEncoding = "base64";
                        }
                    }
                }
                else
                {   // Het is maar 1 attachment
                    //Log2File(2, " 1 attachment");
                    var att_f = S("flexfilespath") + "/" + att;
                    if (objFso.FileExists(att_f))
                    {
                        var attFile = objFso.GetFile(att_f);
                        allAttachSize += attFile.Size;
                        Log2File(1, "Adding attachment: " + attFile.Path + " (" + attFile.Size + " bytes)");
                        var objAttachment = objMail.AddAttachment(attFile.Path);
                        objAttachment.ContentTransferEncoding = "base64";
                    }
                }
            }
        }

v_aanduiding = "sendMail 6";
        if (params.attachments) // Geselecteerde bestanden uit flexfiles meesturen.
        {
            Log2File(2, "geselecteerde attachments meesturen: "+params.attachments.length);
            for (i=0; i<params.attachments.length; i++)
            {
                var att = params.attachments[i];
                var sql = "SELECT r.fac_bijlagen_disk_directory"
                        + "     , r.fac_bijlagen_filename"
                        + "     , r.fac_bijlagen_file_size"
                        + "  FROM fac_bijlagen r"
                        + "     , fac_bijlagen b"
                        + " WHERE b.fac_bijlagen_root_key = r.fac_bijlagen_key"
                        + "   AND b.fac_bijlagen_verwijder IS NULL"
                        + "   AND r.fac_bijlagen_verwijder IS NULL";

                if (att.bijlagen_key)
                {
                    // Exact 1 bijlage
                    Log2File(2, "bijlage " + att.bijlagen_key);
                    sql += " AND b.fac_bijlagen_key = " + att.bijlagen_key;
                }
                else
                {
                    // Alle bijlagen van kenmerk/melding
                    Log2File(2, "bijlagen van " + att.module + " " + att.refkey + " kenmerk " + att.kenmerk_key);
                    sql += " AND b.fac_bijlagen_module = " + safe.quoted_sql(att.module)
                         + " AND b.fac_bijlagen_refkey = " + (att.refkey ? att.refkey : 0)  // voorkomen dat alle bijlagen worden meegestuurd!
                         + (att.kenmerk_key ? " AND b.fac_bijlagen_kenmerk_key = " + att.kenmerk_key : "");
                }

                var oRs = Oracle.Execute(sql);
                while (!oRs.eof)
                {
                    var f_path = oRs("fac_bijlagen_disk_directory").Value;
                    var f_name = oRs("fac_bijlagen_filename").Value;
                    var f_size = oRs("fac_bijlagen_file_size").Value;
                    var filepath = S("flexfilespath") + "/" + f_path + "/" + f_name;
                    if (objFso.FileExists(filepath))
                    {
                        allAttachSize += f_size;
                        Log2File(1, "Adding attachment: " + filepath + " (" + f_size + " bytes)");
                        var objAttachment = objMail.AddAttachment(filepath);
                        objAttachment.ContentTransferEncoding = "base64";
                    }
                    else
                    {
                        Log2File(1, "Warning: attachment '" + filepath + "' not found. Ignoring.");
                    }
                    oRs.MoveNext();
                }
                oRs.Close();
            }
        }
        //
        // Stuur alle flexfiles (type M(ap) en F(file)) als attachment mee (dus van meerdere kenmerken).
        //
v_aanduiding = "sendMail 7";
        if (params.refkey)
        {
            var kenmerk_key = (typeof params.kenmerk_key === "array" ? params.kenmerk_key : [params.kenmerk_key]);
            Log2File(2, "Alle flexfiles meesturen van " + params.module + " " + params.refkey + " kenmerk [" + kenmerk_key.join(",") + "]");
            var sql_km = "";
            if (params.kenmerk_key)
            {
                sql_km = " AND b.fac_bijlagen_kenmerk_key IN (" + kenmerk_key.join(",") + ")" ;
            }
            else
            {
                switch (params.module)
                {
                    case "MLD": sql_km = "SELECT mld_kenmerk_key FROM mld_kenmerk WHERE mld_kenmerk_niveau IN ('O','P')"; break;
                    case "BES": sql_km = "SELECT bes_kenmerk_key FROM bes_kenmerk WHERE bes_kenmerk_type = 'B'";   break;
                    default:    sql_km = "";
                }
                if (sql_km.length)
                    sql_km = " AND b.fac_bijlagen_kenmerk_key IN (" + sql_km + ")";
            }
            //
            var sql = "SELECT r.fac_bijlagen_disk_directory"
                    + "     , r.fac_bijlagen_filename"
                    + "     , r.fac_bijlagen_file_size"
                    + "  FROM fac_bijlagen r"
                    + "     , fac_bijlagen b"
                    + " WHERE b.fac_bijlagen_root_key = r.fac_bijlagen_key"
                    + "   AND b.fac_bijlagen_verwijder IS NULL"
                    + "   AND r.fac_bijlagen_verwijder IS NULL"
                    + "   AND b.fac_bijlagen_module = " + safe.quoted_sql(params.module)
                    + "   AND b.fac_bijlagen_refkey = " + params.refkey
                    + sql_km;
            var oRs = Oracle.Execute(sql);
            while (!oRs.eof)
            {
                var f_path = oRs("fac_bijlagen_disk_directory").Value;
                var f_name = oRs("fac_bijlagen_filename").Value;
                var f_size = oRs("fac_bijlagen_file_size").Value;
                var filepath = S("flexfilespath") + "/" + f_path + "/" + f_name;

                if (objFso.FileExists(filepath))
                {
                    Log2File(1, "Adding attachment: " + filepath + " (" + f_size + " bytes)");
                    if (!params.attachPassword)
                    {   // doe maar gewoon
                        allAttachSize += f_size;
                        var objAttachment = objMail.AddAttachment(filepath);
                        objAttachment.ContentTransferEncoding = "base64";
                    }
                    else
                    {
                        var ZipObjIn = new ActiveXObject("SLNKDWF.Zip");
                        var attStrm = new ActiveXObject("ADODB.Stream");
                        attStrm.Type = 1; // adTypeBinary
                        attStrm.Open();

                        var orgName = f_name; // .encrypted er afhalen
                        var lastIndex = orgName.lastIndexOf(".encrypted");
                        var isEncrypted = (lastIndex != -1 ? (orgName.substring(lastIndex).toLowerCase() == ".encrypted") : false);
                        if (isEncrypted)
                        {   // decrypt
                            orgName = orgName.substring(0, lastIndex);
                            ZipObjIn.Open(filepath);
                            ZipObjIn.DecryptToStream(attStrm, orgName);
                        }
                        else
                        {   // Gewoon lezen
                            attStrm.LoadFromFile(filepath);
                        }
                        attStrm.Position = 0; // We gaan nu over in uitvoermode
                        var ZipObjOut = new ActiveXObject("SLNKDWF.Zip");
                        var tempfile = f_path + "\\" + orgName + ".zip";
                        ZipObjOut.New(tempfile); // Helaas niet *naar* stream
                        ZipObjOut.ZipFromStream(orgName, attStrm, params.attachPassword);
                        attStrm.Close();
                        ZipObjOut.Close();
                        var attFile = objFso.GetFile(tempfile);
                        allAttachSize += attFile.Size;
                        var objAttachment = objMail.AddAttachment(tempfile);
                        objAttachment.ContentTransferEncoding = "base64";
                        objFso.DeleteFile(tempfile); // objMail houdt hem nog even gelocked maar straks is hij wel weg
                    }
                }
                else
                {
                    Log2File(1, "Warning: attachment '" + filepath + "' not found. Ignoring.");
                }
                oRs.MoveNext();
            }
            oRs.Close();
        }
        if (allAttachSize > 0)
        {
            Log2File(1, "Total attachments {0}KB becomes {1}KB after base64 encoding".format(Math.round(allAttachSize/1024), Math.round(allAttachSize/1024 / 3 * 4)));
        }

        objMail.From = MailSender;
        if (MailReply)
            objMail.ReplyTo = MailReply;
        objMail.To = p_mailto;

        if (S("puo_forcemailaddress")) // Dat wordt veel te ingewikkeld
        {
            if (params.cc)
                Log2File(1, "Not sending to cc ({0}) because puo_forcemailaddress is set".format(params.cc));
            if (params.bcc)
                Log2File(1, "Not sending to bcc ({0}) because puo_forcemailaddress is set".format(params.bcc));
        }
        else
        {
            if (params.cc)
                Log2File(1, "CC to {0}".format(params.cc));
            if (params.bcc)
                Log2File(1, "BCC toc {0}".format(params.bcc));
            objMail.CC = params.cc || "";
            objMail.BCC = params.bcc || "";
        }
        objMail.subject = p_subject || "(no subject)";
        //
        if (params.attachStream)
        {
            if (params.attachStream.Size != 0)
            {
                Log2File(2, "Before set addBodyPart");
                var cdoBodyPart = objMail.BodyPart.AddBodyPart(-1);
                cdoBodyPart.ContentMediaType = "application/octet-stream";
                cdoBodyPart.ContentTransferEncoding = "7bit";
                objStrm = cdoBodyPart.GetDecodedContentStream();
                params.attachStream.Position = 0;
                params.attachStream.copyTo(objStrm);
                objStrm.Flush();
                objStrm.Close();
                var objFlds = cdoBodyPart.Fields;
                objFlds("urn:schemas:mailheader:content-disposition").Value = "attachment; filename=\"" + params.attachFileName + "\"";
                objFlds.Update();
            }
        }
v_aanduiding = "sendMail 8";

        if (params.receiptto)
        {
            // ontvangst bevestiging vragen en versturen naar dit adres
            objMail.Fields("urn:schemas:mailheader:disposition-notification-to").Value = params.receiptto;
            objMail.Fields("urn:schemas:mailheader:return-receipt-to").Value = params.receiptto;
            objMail.Fields.Update();
        }

v_aanduiding = "sendMail 9";
        var forcedgroup = true;
        if (S("puo_forcemailaddress") && !params.ignoreOverrule)
        {
            var find_email = ( objMail.To.indexOf("<") >= 0
                             ? objMail.To.substring(objMail.To.indexOf("<")+1, objMail.To.indexOf(">"))
                             : objMail.To
                             );
            // als prs_perslid_key bij mailadres=objMail.To in de autorisatiegroep S("puo_forceallowedgroep") zit dan niet overrulen
            var sql = "SELECT COUNT(*) aantal"
                    + "  FROM fac_groep fg"
                    + "     , fac_gebruikersgroep gg"
                    + "     , prs_perslid pp"
                    + " WHERE fg.fac_groep_key = gg.fac_groep_key"
                    + "   AND gg.prs_perslid_key = pp.prs_perslid_key"
                    + "   AND fg.fac_groep_upper = " + safe.quoted_sql_upper(S("puo_forceallowedgroep"))
                    + "   AND UPPER(pp.prs_perslid_email) = " + safe.quoted_sql_upper(find_email);
            var oRs = Oracle.Execute(sql);
            if (oRs("aantal").Value == 0)
            {
                forcedgroup = false;
                objMail.Fields("urn:schemas:mailheader:X-FCLT-original-to").Value = objMail.To;
                objMail.To = S("puo_forcemailaddress");
            }
            oRs.Close();
        }

v_aanduiding = "sendMail 10";
        if (S("puo_forcefromaddress"))
        {
            objMail.Fields("urn:schemas:mailheader:X-FCLT-original-from").Value = objMail.From;
            objMail.Fields("urn:schemas:mailheader:X-FCLT-original-replyto").Value = objMail.ReplyTo;
            objMail.From = S("puo_forcefromaddress").format(customerId);
            objMail.ReplyTo = S("puo_forcefromaddress").format(customerId);
        }
        //
        var forcemsg = "Sending email '" + p_subject + "' from: " + MailSender + " to: " + p_mailto;
        if (S("puo_forcemailaddress") || S("puo_forcefromaddress"))
        {
            var forcedgrouptxt = (forcedgroup ? " forced by allowed group " + S("puo_forceallowedgroep") : "");
            forcemsg += "\n        (effective from: " + objMail.From + " to: " + objMail.To + forcedgrouptxt + ")";
        }

        Log2File(1, forcemsg);

        // Handig voor intern gebruik. Komt in de e-mail headers terecht
        objMail.Fields("urn:schemas:mailheader:X-FCLT-cust").Value = customerId;
        if ("srtnotificatie" in params)
            objMail.Fields("urn:schemas:mailheader:X-FCLT-noticode").Value = params.srtnotificatie;
        if ("notimode" in params)
            objMail.Fields("urn:schemas:mailheader:X-FCLT-notimode").Value = params.notimode;
        if ("fcltid" in params)
            objMail.Fields("urn:schemas:mailheader:X-FCLT-fcltid").Value = params.fcltid;

v_aanduiding = "sendMail 11";
        objMail.Fields.Update();
v_aanduiding = "sendMail 12";
        //
        //
        if (p_mailto)
        {
            try
            {
v_aanduiding = "sendMail 13";
                objMail.Send();
v_aanduiding = "sendMail 14";
                // helaas undefined Log2File(1, "E-mail size: " + objMail.Size);
            }
            catch (e)
            {
                Log2File(1, "E-mail sending failed: " + e.description, "W");
                throw e; // Throw again
            }
            Log2File(2, "Sent.");
        }
        else
        {
            Log2File(2, "Nobody to send to.");
        }
        Mailsend = true;
    } // !p_mailto || !MailSender)
    objMail = null;
    Log2File(2, "*< sendMail");

    return Mailsend;
}
